Fixed conflicts after merge with master

This commit is contained in:
Enrico Turri 2020-03-09 16:03:15 +01:00
commit 5693545d15
71 changed files with 3265 additions and 2634 deletions

View file

@ -328,13 +328,21 @@ find_package(TBB REQUIRED)
# add_definitions(-DTBB_USE_CAPTURED_EXCEPTION=0) # add_definitions(-DTBB_USE_CAPTURED_EXCEPTION=0)
find_package(CURL REQUIRED) find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIRS})
add_library(libcurl INTERFACE)
target_link_libraries(libcurl INTERFACE CURL::libcurl)
if (NOT WIN32)
# Required by libcurl
find_package(ZLIB REQUIRED)
target_link_libraries(libcurl INTERFACE ZLIB::ZLIB)
endif()
if (SLIC3R_STATIC) if (SLIC3R_STATIC)
if (NOT APPLE) if (NOT APPLE)
# libcurl is always linked dynamically to the system libcurl on OSX. # libcurl is always linked dynamically to the system libcurl on OSX.
# On other systems, libcurl is linked statically if SLIC3R_STATIC is set. # On other systems, libcurl is linked statically if SLIC3R_STATIC is set.
add_definitions(-DCURL_STATICLIB) target_compile_definitions(libcurl INTERFACE CURL_STATICLIB)
endif() endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Linux") if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
# As of now, our build system produces a statically linked libcurl, # As of now, our build system produces a statically linked libcurl,
@ -342,7 +350,8 @@ if (SLIC3R_STATIC)
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}") message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
message("OpenSSL libraries: ${OPENSSL_LIBRARIES}") message("OpenSSL libraries: ${OPENSSL_LIBRARIES}")
include_directories(${OPENSSL_INCLUDE_DIR}) target_include_directories(libcurl INTERFACE ${OPENSSL_INCLUDE_DIR})
target_link_libraries(libcurl INTERFACE ${OPENSSL_LIBRARIES})
endif() endif()
endif() endif()

View file

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

After

Width:  |  Height:  |  Size: 753 B

View file

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

After

Width:  |  Height:  |  Size: 753 B

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Poedit 2.2.1\n" "X-Generator: Poedit 2.3\n"
"Project-Id-Version: \n" "Project-Id-Version: \n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: \n" "PO-Revision-Date: \n"
@ -1561,6 +1561,10 @@ msgstr "Kubická"
msgid "Current mode is %s" msgid "Current mode is %s"
msgstr "Aktuální režim je %s" msgstr "Aktuální režim je %s"
#: src/slic3r/GUI/Tab.cpp:959
msgid "Current preset is inherited from"
msgstr "Aktuální nastavení je zděděné od"
#: src/slic3r/GUI/Tab.cpp:957 #: src/slic3r/GUI/Tab.cpp:957
msgid "Current preset is inherited from the default preset." msgid "Current preset is inherited from the default preset."
msgstr "Aktuální nastavení je zděděno z výchozího nastavení." msgstr "Aktuální nastavení je zděděno z výchozího nastavení."
@ -2136,6 +2140,18 @@ msgstr "Upravit značku - Pravé tlačítko myši"
msgid "Editing" msgid "Editing"
msgstr "Editace" msgstr "Editace"
#: src/slic3r/GUI/MainFrame.cpp:547
msgid "Ejec&t SD card / Flash drive"
msgstr "Vysunou&t SD kartu / Flash disk"
#: src/slic3r/GUI/KBShortcutsDialog.cpp:126
msgid "Eject SD card / Flash drive"
msgstr "Vysunout SD kartu / Flash disk"
#: src/slic3r/GUI/MainFrame.cpp:547
msgid "Eject SD card / Flash drive after the G-code was exported to it."
msgstr "Vysunout SD kartu / Flash disk po vyexportování G-codu."
#: src/libslic3r/PrintConfig.cpp:118 #: src/libslic3r/PrintConfig.cpp:118
msgid "Elephant foot compensation" msgid "Elephant foot compensation"
msgstr "Kompenzace rozplácnutí první vrstvy" msgstr "Kompenzace rozplácnutí první vrstvy"
@ -2426,6 +2442,10 @@ msgstr "Exportovat stávající plochu jako AMF"
msgid "Export current plate as G-code" msgid "Export current plate as G-code"
msgstr "Exportovat stávající plochu do G-code" msgstr "Exportovat stávající plochu do G-code"
#: src/slic3r/GUI/MainFrame.cpp:521
msgid "Export current plate as G-code to SD card / Flash drive"
msgstr "Exportovat aktuální podložku jako G-code na SD kartu / Flash disk"
#: src/slic3r/GUI/MainFrame.cpp:486 #: src/slic3r/GUI/MainFrame.cpp:486
msgid "Export current plate as STL" msgid "Export current plate as STL"
msgstr "Exportovat stávající plochu jako STL" msgstr "Exportovat stávající plochu jako STL"
@ -2447,6 +2467,10 @@ msgstr "Exportovat úplné zdrojové cesty modelů a dílů do souborů 3mf a am
msgid "Export G-code" msgid "Export G-code"
msgstr "Exportovat G-code" msgstr "Exportovat G-code"
#: src/slic3r/GUI/MainFrame.cpp:521
msgid "Export G-code to SD card / Flash drive"
msgstr "Exportovat G-code na SD kartu / Flash disk"
#: src/libslic3r/PrintConfig.cpp:3320 #: src/libslic3r/PrintConfig.cpp:3320
msgid "Export OBJ" msgid "Export OBJ"
msgstr "Exportovat OBJ" msgstr "Exportovat OBJ"
@ -2956,6 +2980,15 @@ msgstr ""
"na levé straně: indikuje nesystémové (jiné než výchozí) přednastavení,\n" "na levé straně: indikuje nesystémové (jiné než výchozí) přednastavení,\n"
"na pravé straně: indikuje, že nastavení nebylo změněno." "na pravé straně: indikuje, že nastavení nebylo změněno."
#. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3267
msgid ""
"for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: indicates that the settings hasn't been modified."
msgstr ""
"na levé straně: indikuje nesystémové (jiné než výchozí) přednastavení,\n"
"na pravé straně: indikuje, že nastavení nebylo změněno."
#: src/slic3r/GUI/ConfigManipulation.cpp:136 #: src/slic3r/GUI/ConfigManipulation.cpp:136
msgid "" msgid ""
"For the Wipe Tower to work with the soluble supports, the support layers\n" "For the Wipe Tower to work with the soluble supports, the support layers\n"
@ -3589,7 +3622,9 @@ msgstr "indikuje, že nastavení jsou stejná jako systémové (výchozí) hodno
msgid "" msgid ""
"indicates that the settings were changed and are not equal to the last saved preset for the current option group.\n" "indicates that the settings were changed and are not equal to the last saved preset for the current option group.\n"
"Click the BACK ARROW icon to reset all settings for the current option group to the last saved preset." "Click the BACK ARROW icon to reset all settings for the current option group to the last saved preset."
msgstr "indikuje, že došlo ke změně nastavení, které není shodné s naposledy uloženým přednastavením pro aktuální skupinu nastavení. Klikněte na ikonu ŠIPKY ZPĚT pro reset všech nastavení pro aktuální skupinu nastavení na naposledy uložené přednastavení." msgstr ""
"indikuje, že došlo ke změně nastavení, které není shodné s naposledy uloženým přednastavením pro aktuální skupinu nastavení.\n"
"Klikněte na ikonu ŠIPKY ZPĚT pro reset všech nastavení pro aktuální skupinu nastavení na naposledy uložené přednastavení."
#: src/slic3r/GUI/ConfigManipulation.cpp:211 #: src/slic3r/GUI/ConfigManipulation.cpp:211
#: src/slic3r/GUI/GUI_ObjectList.cpp:35 src/slic3r/GUI/GUI_ObjectList.cpp:96 #: src/slic3r/GUI/GUI_ObjectList.cpp:35 src/slic3r/GUI/GUI_ObjectList.cpp:96
@ -4118,6 +4153,10 @@ msgstr "Maximum"
msgid "Max bridge length" msgid "Max bridge length"
msgstr "Maximální délka mostu" msgstr "Maximální délka mostu"
#: src/libslic3r/PrintConfig.cpp:2658
msgid "Max bridges on a pillar"
msgstr "Max počet mostů na sloupu"
#: src/libslic3r/PrintConfig.cpp:2822 #: src/libslic3r/PrintConfig.cpp:2822
msgid "Max merge distance" msgid "Max merge distance"
msgstr "Maximální vzdálenost pro sloučení" msgstr "Maximální vzdálenost pro sloučení"
@ -4286,6 +4325,10 @@ msgstr "Maximální ryv Y"
msgid "Maximum jerk Z" msgid "Maximum jerk Z"
msgstr "Maximální ryv Z" msgstr "Maximální ryv Z"
#: src/libslic3r/PrintConfig.cpp:2660
msgid "Maximum number of bridges that can be placed on a pillar. Bridges hold support point pinheads and connect to pillars as small branches."
msgstr "Maximální počet mostů, které mohou být umístěny na podpěrný sloup. Mosty drží hroty podpěr a připojují se ke sloupům jako malé větve."
#: src/libslic3r/PrintConfig.cpp:598 #: src/libslic3r/PrintConfig.cpp:598
msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit." msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit."
msgstr "Maximální povolený objem průtoku pro tento filament. Omezuje maximální rychlost průtoku pro tisk až na minimální rychlost průtoku pro tisk a filament. Zadejte nulu pro nastavení bez omezení." msgstr "Maximální povolený objem průtoku pro tento filament. Omezuje maximální rychlost průtoku pro tisk až na minimální rychlost průtoku pro tisk a filament. Zadejte nulu pro nastavení bez omezení."
@ -4957,6 +5000,11 @@ msgstr "současného Objektu"
msgid "Offset" msgid "Offset"
msgstr "Odsazení" msgstr "Odsazení"
#: src/slic3r/GUI/Tab.cpp:1755
#, c-format
msgid "On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain."
msgstr "V tomto systému používá %s certifikáty HTTPS ze systému Certificate Store nebo Keychain."
#: src/slic3r/GUI/DoubleSlider.cpp:950 #: src/slic3r/GUI/DoubleSlider.cpp:950
msgid "One layer mode" msgid "One layer mode"
msgstr "Zobrazení po jedné vrstvě" msgstr "Zobrazení po jedné vrstvě"
@ -6430,6 +6478,16 @@ msgstr ""
"NE, pokud chcete, aby se všechny změny nástroje přepnout na změny barev,\n" "NE, pokud chcete, aby se všechny změny nástroje přepnout na změny barev,\n"
"nebo ZRUŠIT pro ponechání beze změny." "nebo ZRUŠIT pro ponechání beze změny."
#: src/slic3r/GUI/DoubleSlider.cpp:1917
msgid ""
"Select YES if you want to delete all saved tool changes, \n"
"NO if you want all tool changes switch to color changes, \n"
"or CANCEL to leave it unchanged."
msgstr ""
"Vyberte ANO, pokud chcete odstranit všechny uložené změny nástroje,\n"
"NE, pokud chcete, aby se všechny změny nástroje přepnout na změny barev,\n"
"nebo ZRUŠIT pro ponechání beze změny."
#: src/slic3r/GUI/Selection.cpp:146 #: src/slic3r/GUI/Selection.cpp:146
msgid "Selection-Add" msgid "Selection-Add"
msgstr "Výběř - Přidání" msgstr "Výběř - Přidání"
@ -7569,7 +7627,7 @@ msgstr "Textura"
#: src/slic3r/GUI/ConfigManipulation.cpp:208 #: src/slic3r/GUI/ConfigManipulation.cpp:208
msgid "The %1% infill pattern is not supposed to work at 100%% density." msgid "The %1% infill pattern is not supposed to work at 100%% density."
msgstr "Vzor výplně %1% není určen pro 100 %% hustotu výplně." msgstr "Vzor výplně %1% není určen pro 100%% hustotu výplně."
#: src/slic3r/GUI/FirmwareDialog.cpp:548 #: src/slic3r/GUI/FirmwareDialog.cpp:548
#, c-format #, c-format
@ -7737,6 +7795,14 @@ msgstr "Vybraný objekt nemůže být rozdělen, protože obsahuje více než je
msgid "The selected object couldn't be split because it contains only one part." msgid "The selected object couldn't be split because it contains only one part."
msgstr "Vybraný objekt nemůže být rozdělen, protože obsahuje pouze jednu část." msgstr "Vybraný objekt nemůže být rozdělen, protože obsahuje pouze jednu část."
#: src/slic3r/GUI/MainFrame.cpp:432
msgid ""
"The selected project is no longer available.\n"
"Do you want to remove it from the recent projects list ?"
msgstr ""
"Vybraný projekt již není k dispozici.\n"
"Chcete ho odstranit ze seznamu posledních projektů?"
#: src/slic3r/GUI/MainFrame.cpp:422 #: src/slic3r/GUI/MainFrame.cpp:422
msgid "The selected project is no more available" msgid "The selected project is no more available"
msgstr "Vybraný projekt již není dostupný" msgstr "Vybraný projekt již není dostupný"
@ -8087,6 +8153,10 @@ msgstr "Nejmenší tisknutelná výška vrstvy pro tento extruder. Omezuje rozli
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed." msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "To je obvykle způsobeno zanedbatelně malým množstvím extrudovaného materiálu nebo chybným modelem. Zkuste model opravit nebo změnit jeho orientaci na podložce." msgstr "To je obvykle způsobeno zanedbatelně malým množstvím extrudovaného materiálu nebo chybným modelem. Zkuste model opravit nebo změnit jeho orientaci na podložce."
#: src/libslic3r/GCode.cpp:639
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "To je obvykle způsobeno zanedbatelně malým množstvím extrudovaného materiálu nebo chybným modelem. Zkuste model opravit nebo změnit jeho orientaci na podložce."
#: src/libslic3r/PrintConfig.cpp:2215 #: src/libslic3r/PrintConfig.cpp:2215
msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools." msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools."
msgstr "Tato matice popisuje objemy (v kubických milimetrech) nutné k vyčištění nového filamentu na čistící věži pro danou dvojici nástrojů." msgstr "Tato matice popisuje objemy (v kubických milimetrech) nutné k vyčištění nového filamentu na čistící věži pro danou dvojici nástrojů."
@ -8228,6 +8298,10 @@ msgstr "Na objekty"
msgid "To parts" msgid "To parts"
msgstr "Na části" msgstr "Na části"
#: src/slic3r/GUI/Tab.cpp:1756
msgid "To use a custom CA file, please import your CA file into Certificate Store / Keychain."
msgstr "Chcete-li použít vlastní soubor CA, importujte soubor CA do Certificate Store / Keychain."
#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263
#, c-format #, c-format
msgid "Toggle %c axis mirroring" msgid "Toggle %c axis mirroring"

View file

@ -5,7 +5,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.2.1\n" "X-Generator: Poedit 2.3\n"
"Project-Id-Version: \n" "Project-Id-Version: \n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: \n" "PO-Revision-Date: \n"
@ -1557,6 +1557,10 @@ msgstr "Kubisch"
msgid "Current mode is %s" msgid "Current mode is %s"
msgstr "Aktueller Modus ist %s" msgstr "Aktueller Modus ist %s"
#: src/slic3r/GUI/Tab.cpp:959
msgid "Current preset is inherited from"
msgstr "Aktuelle Voreinstellung ist abgeleitet von"
#: src/slic3r/GUI/Tab.cpp:957 #: src/slic3r/GUI/Tab.cpp:957
msgid "Current preset is inherited from the default preset." msgid "Current preset is inherited from the default preset."
msgstr "Aktuelle Voreinstellung ist abgeleitet von der Standardvoreinstellung." msgstr "Aktuelle Voreinstellung ist abgeleitet von der Standardvoreinstellung."
@ -2952,6 +2956,15 @@ msgstr ""
"Beim linken Knopf: zeigt eine Nicht-System- (oder Nicht-Standard-) Einstellung an.\n" "Beim linken Knopf: zeigt eine Nicht-System- (oder Nicht-Standard-) Einstellung an.\n"
"Beim rechten Knopf: zeigt an, dass die Einstellung nicht geändert wurde." "Beim rechten Knopf: zeigt an, dass die Einstellung nicht geändert wurde."
#. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3267
msgid ""
"for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: indicates that the settings hasn't been modified."
msgstr ""
"Beim linken Knopf: zeigt eine Nicht-System- (oder Nicht-Standard-) Einstellung an.\n"
"Beim rechten Knopf: zeigt an, dass die Einstellung nicht geändert wurde."
#: src/slic3r/GUI/ConfigManipulation.cpp:136 #: src/slic3r/GUI/ConfigManipulation.cpp:136
msgid "" msgid ""
"For the Wipe Tower to work with the soluble supports, the support layers\n" "For the Wipe Tower to work with the soluble supports, the support layers\n"
@ -3582,7 +3595,7 @@ msgid ""
"indicates that the settings were changed and are not equal to the last saved preset for the current option group.\n" "indicates that the settings were changed and are not equal to the last saved preset for the current option group.\n"
"Click the BACK ARROW icon to reset all settings for the current option group to the last saved preset." "Click the BACK ARROW icon to reset all settings for the current option group to the last saved preset."
msgstr "" msgstr ""
"zeigt an, dass die Einstellungen geändert wurden und nicht mit dem zuletzt gespeicherten Preset für die aktuelle Optionsgruppe übereinstimmen. \n" "zeigt an, dass die Einstellungen geändert wurden und nicht mit dem zuletzt gespeicherten Preset für die aktuelle Optionsgruppe übereinstimmen.\n"
"Klicken Sie auf das Symbol PFEIL ZURÜCK, um alle Einstellungen für die aktuelle Optionsgruppe auf das zuletzt gespeicherte Preset zurückzusetzen." "Klicken Sie auf das Symbol PFEIL ZURÜCK, um alle Einstellungen für die aktuelle Optionsgruppe auf das zuletzt gespeicherte Preset zurückzusetzen."
#: src/slic3r/GUI/ConfigManipulation.cpp:211 #: src/slic3r/GUI/ConfigManipulation.cpp:211
@ -4112,6 +4125,10 @@ msgstr "Max"
msgid "Max bridge length" msgid "Max bridge length"
msgstr "Max Überbrückungslänge" msgstr "Max Überbrückungslänge"
#: src/libslic3r/PrintConfig.cpp:2658
msgid "Max bridges on a pillar"
msgstr "Max Brücken auf einem Pfeiler"
#: src/libslic3r/PrintConfig.cpp:2822 #: src/libslic3r/PrintConfig.cpp:2822
msgid "Max merge distance" msgid "Max merge distance"
msgstr "Maximaler Zusammenfügeabstand" msgstr "Maximaler Zusammenfügeabstand"
@ -4280,6 +4297,10 @@ msgstr "Maximaler Ruck Y"
msgid "Maximum jerk Z" msgid "Maximum jerk Z"
msgstr "Maximaler Ruck Z" msgstr "Maximaler Ruck Z"
#: src/libslic3r/PrintConfig.cpp:2660
msgid "Maximum number of bridges that can be placed on a pillar. Bridges hold support point pinheads and connect to pillars as small branches."
msgstr "Maximale Anzahl von Brücken, die auf einen Pfeiler gesetzt werden können. Brücken halten Stützpunkt-Nadelköpfe und verbinden sich als kleine Äste mit den Pfeilern."
#: src/libslic3r/PrintConfig.cpp:598 #: src/libslic3r/PrintConfig.cpp:598
msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit." msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit."
msgstr "Maximale volumetrische Geschwindigkeit, die für dieses Filament zulässig ist. Begrenzt die maximale volumetrische Geschwindigkeit eines Drucks auf das Minimum von Druck- und Filament-Volumengeschwindigkeit. Wird auf null gesetzt, wenn es keine Begrenzung gibt." msgstr "Maximale volumetrische Geschwindigkeit, die für dieses Filament zulässig ist. Begrenzt die maximale volumetrische Geschwindigkeit eines Drucks auf das Minimum von Druck- und Filament-Volumengeschwindigkeit. Wird auf null gesetzt, wenn es keine Begrenzung gibt."
@ -4951,6 +4972,11 @@ msgstr "des aktuellen Objekts"
msgid "Offset" msgid "Offset"
msgstr "Offset" msgstr "Offset"
#: src/slic3r/GUI/Tab.cpp:1755
#, c-format
msgid "On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain."
msgstr "Auf diesem System verwendet %s HTTPS-Zertifikate aus dem System Zertifikatsspeicher oder Schlüsselbund."
#: src/slic3r/GUI/DoubleSlider.cpp:950 #: src/slic3r/GUI/DoubleSlider.cpp:950
msgid "One layer mode" msgid "One layer mode"
msgstr "Eine Schicht Modus" msgstr "Eine Schicht Modus"
@ -6421,6 +6447,16 @@ msgstr ""
"NEIN, wenn Sie möchten, dass alle Werkzeugänderungen auf Farbwechsel umgestellt werden, \n" "NEIN, wenn Sie möchten, dass alle Werkzeugänderungen auf Farbwechsel umgestellt werden, \n"
"oder ABBRECHEN, um sie unverändert zu lassen." "oder ABBRECHEN, um sie unverändert zu lassen."
#: src/slic3r/GUI/DoubleSlider.cpp:1917
msgid ""
"Select YES if you want to delete all saved tool changes, \n"
"NO if you want all tool changes switch to color changes, \n"
"or CANCEL to leave it unchanged."
msgstr ""
"Wählen Sie JA, wenn Sie alle gespeicherten Werkzeugänderungen löschen möchten, \n"
"NEIN, wenn Sie möchten, dass alle Werkzeugänderungen auf Farbwechsel umgestellt werden, \n"
"oder ABBRECHEN, um sie unverändert zu lassen."
#: src/slic3r/GUI/Selection.cpp:146 #: src/slic3r/GUI/Selection.cpp:146
msgid "Selection-Add" msgid "Selection-Add"
msgstr "Auswahl hinzufügen" msgstr "Auswahl hinzufügen"
@ -7733,6 +7769,14 @@ msgstr "Das ausgewählte Objekt konnte nicht getrennt werden, weil es aus mehr a
msgid "The selected object couldn't be split because it contains only one part." msgid "The selected object couldn't be split because it contains only one part."
msgstr "Das ausgewählte Objekt konnte nicht getrennt werden, da es nur aus einem Teil besteht." msgstr "Das ausgewählte Objekt konnte nicht getrennt werden, da es nur aus einem Teil besteht."
#: src/slic3r/GUI/MainFrame.cpp:432
msgid ""
"The selected project is no longer available.\n"
"Do you want to remove it from the recent projects list ?"
msgstr ""
"Das ausgewählte Projekt ist nicht mehr verfügbar.\n"
"Wollen Sie es aus der Liste der letzten Projekte entfernen ?"
#: src/slic3r/GUI/MainFrame.cpp:422 #: src/slic3r/GUI/MainFrame.cpp:422
msgid "The selected project is no more available" msgid "The selected project is no more available"
msgstr "Das ausgewählte Projekt ist nicht mehr verfügbar" msgstr "Das ausgewählte Projekt ist nicht mehr verfügbar"
@ -8077,6 +8121,10 @@ msgstr "Dies ist die niedrigste druckbare Schichthöhe für diesen Extruder und
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed." msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "Dies wird in der Regel durch vernachlässigbar kleine Extrusionen oder durch ein fehlerhaftes Modell verursacht. Versuchen Sie, das Modell zu reparieren oder seine Ausrichtung auf dem Druckbett zu ändern." msgstr "Dies wird in der Regel durch vernachlässigbar kleine Extrusionen oder durch ein fehlerhaftes Modell verursacht. Versuchen Sie, das Modell zu reparieren oder seine Ausrichtung auf dem Druckbett zu ändern."
#: src/libslic3r/GCode.cpp:639
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "Dies wird in der Regel durch vernachlässigbar kleine Extrusionen oder durch ein fehlerhaftes Modell verursacht. Versuchen Sie, das Modell zu reparieren oder seine Ausrichtung auf dem Druckbett zu ändern."
#: src/libslic3r/PrintConfig.cpp:2215 #: src/libslic3r/PrintConfig.cpp:2215
msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools." msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools."
msgstr "Diese Matrix beschreibt die Volumina (in Kubikmillimetern), die benötigt werden, um das neue Filament auf dem Reinigungsturm für ein bestimmtes Werkzeugpaar zu reinigen." msgstr "Diese Matrix beschreibt die Volumina (in Kubikmillimetern), die benötigt werden, um das neue Filament auf dem Reinigungsturm für ein bestimmtes Werkzeugpaar zu reinigen."
@ -8218,6 +8266,10 @@ msgstr "Zu Objekten"
msgid "To parts" msgid "To parts"
msgstr "Zu Teilen" msgstr "Zu Teilen"
#: src/slic3r/GUI/Tab.cpp:1756
msgid "To use a custom CA file, please import your CA file into Certificate Store / Keychain."
msgstr "Um eine benutzerdefinierte CA-Datei zu verwenden, importieren Sie bitte Ihre CA-Datei in den Zertifikatsspeicher / Schlüsselbund."
#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263
#, c-format #, c-format
msgid "Toggle %c axis mirroring" msgid "Toggle %c axis mirroring"

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 1.8.7.1\n" "X-Generator: Poedit 2.3\n"
"Project-Id-Version: \n" "Project-Id-Version: \n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: \n" "PO-Revision-Date: \n"
@ -1561,6 +1561,10 @@ msgstr "Cubique"
msgid "Current mode is %s" msgid "Current mode is %s"
msgstr "Le mode actuel est %s" msgstr "Le mode actuel est %s"
#: src/slic3r/GUI/Tab.cpp:959
msgid "Current preset is inherited from"
msgstr "Le préréglage actuel est hérité de"
#: src/slic3r/GUI/Tab.cpp:957 #: src/slic3r/GUI/Tab.cpp:957
msgid "Current preset is inherited from the default preset." msgid "Current preset is inherited from the default preset."
msgstr "Le préréglage actuel est hérité du préréglage par défaut." msgstr "Le préréglage actuel est hérité du préréglage par défaut."
@ -2956,6 +2960,15 @@ msgstr ""
"pour le bouton gauche : indique un préréglage non-système (ou non par défaut),\n" "pour le bouton gauche : indique un préréglage non-système (ou non par défaut),\n"
"pour le bouton droit : indique que le réglage n'a pas été modifié." "pour le bouton droit : indique que le réglage n'a pas été modifié."
#. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3267
msgid ""
"for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: indicates that the settings hasn't been modified."
msgstr ""
"pour le bouton gauche : indique un préréglage non-système (ou non par défaut),\n"
"pour le bouton droit : indique que le réglage n'a pas été modifié."
#: src/slic3r/GUI/ConfigManipulation.cpp:136 #: src/slic3r/GUI/ConfigManipulation.cpp:136
msgid "" msgid ""
"For the Wipe Tower to work with the soluble supports, the support layers\n" "For the Wipe Tower to work with the soluble supports, the support layers\n"
@ -3578,7 +3591,6 @@ msgid ""
"Click the UNLOCKED LOCK icon to reset all settings for current option group to the system (or default) values." "Click the UNLOCKED LOCK icon to reset all settings for current option group to the system (or default) values."
msgstr "" msgstr ""
"indique que certains paramètres ont été modifiés et ne sont pas égaux aux valeurs du système (ou par défaut) pour le groupe d'options actuel.\n" "indique que certains paramètres ont été modifiés et ne sont pas égaux aux valeurs du système (ou par défaut) pour le groupe d'options actuel.\n"
"\n"
"Cliquez sur l'icône CADENAS OUVERT pour régler tous les paramètres pour le groupe d'options actuel sur les valeurs du système (ou par défaut)." "Cliquez sur l'icône CADENAS OUVERT pour régler tous les paramètres pour le groupe d'options actuel sur les valeurs du système (ou par défaut)."
#. TRN Description for "LOCKED LOCK" #. TRN Description for "LOCKED LOCK"
@ -4055,15 +4067,15 @@ msgstr "Verrouiller les supports sous de nouveaux îlots"
#: src/slic3r/GUI/Tab.cpp:3252 #: src/slic3r/GUI/Tab.cpp:3252
msgid "LOCKED LOCK" msgid "LOCKED LOCK"
msgstr "VERROU VERROUILLE" msgstr "CADENAS FERMÉ"
#: src/slic3r/GUI/Tab.cpp:3280 #: src/slic3r/GUI/Tab.cpp:3280
msgid "LOCKED LOCK icon indicates that the settings are the same as the system (or default) values for the current option group" msgid "LOCKED LOCK icon indicates that the settings are the same as the system (or default) values for the current option group"
msgstr "L'icône VERROU VERROUILLE indique que les réglages sont les mêmes que les valeurs système (ou par défaut) pour le groupe d'options actuel" msgstr "L'icône CADENAS FERMÉ indique que les réglages sont les mêmes que les valeurs système (ou par défaut) pour le groupe d'options actuel"
#: src/slic3r/GUI/Tab.cpp:3296 #: src/slic3r/GUI/Tab.cpp:3296
msgid "LOCKED LOCK icon indicates that the value is the same as the system (or default) value." msgid "LOCKED LOCK icon indicates that the value is the same as the system (or default) value."
msgstr "L'icône VERROU VERROUILLÉ indique que la valeur est la même que la valeur système (ou par défaut)." msgstr "L'icône CADENAS FERMÉ indique que la valeur est la même que la valeur système (ou par défaut)."
#: src/libslic3r/PrintConfig.cpp:3508 #: src/libslic3r/PrintConfig.cpp:3508
msgid "Logging level" msgid "Logging level"
@ -4122,6 +4134,10 @@ msgstr "Maximum"
msgid "Max bridge length" msgid "Max bridge length"
msgstr "Longueur maximum de pont" msgstr "Longueur maximum de pont"
#: src/libslic3r/PrintConfig.cpp:2658
msgid "Max bridges on a pillar"
msgstr "Nombre de ponts maximum par pilier"
#: src/libslic3r/PrintConfig.cpp:2822 #: src/libslic3r/PrintConfig.cpp:2822
msgid "Max merge distance" msgid "Max merge distance"
msgstr "Distance maximum de fusion" msgstr "Distance maximum de fusion"
@ -4290,6 +4306,10 @@ msgstr "Mouvement brusque maximum Y"
msgid "Maximum jerk Z" msgid "Maximum jerk Z"
msgstr "Mouvement brusque maximum Z" msgstr "Mouvement brusque maximum Z"
#: src/libslic3r/PrintConfig.cpp:2660
msgid "Maximum number of bridges that can be placed on a pillar. Bridges hold support point pinheads and connect to pillars as small branches."
msgstr "Le nombre de ponts maximum pouvant être placés sur un pilier. Les ponts soutiennent les têtes des points de support et sont connectés aux piliers comme de petites branches."
#: src/libslic3r/PrintConfig.cpp:598 #: src/libslic3r/PrintConfig.cpp:598
msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit." msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit."
msgstr "Vitesse volumétrique maximale autorisée pour ce filament. Limite la vitesse volumétrique d'une impression au minimum des vitesses volumétriques d'impression et de filament. Mettez à zéro pour enlever la limite." msgstr "Vitesse volumétrique maximale autorisée pour ce filament. Limite la vitesse volumétrique d'une impression au minimum des vitesses volumétriques d'impression et de filament. Mettez à zéro pour enlever la limite."
@ -4961,6 +4981,11 @@ msgstr "d'un Objet en cours"
msgid "Offset" msgid "Offset"
msgstr "Décalage" msgstr "Décalage"
#: src/slic3r/GUI/Tab.cpp:1755
#, c-format
msgid "On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain."
msgstr "Dans ce système, %s utilise des certificats HTTPS issus du système Magasin de Certificats ou Trousseau."
#: src/slic3r/GUI/DoubleSlider.cpp:950 #: src/slic3r/GUI/DoubleSlider.cpp:950
msgid "One layer mode" msgid "One layer mode"
msgstr "Mode couche unique" msgstr "Mode couche unique"
@ -6437,6 +6462,16 @@ msgstr ""
"NON si vous souhaitez que tous les changements d'outil soient remplacés par des modifications de couleur, \n" "NON si vous souhaitez que tous les changements d'outil soient remplacés par des modifications de couleur, \n"
"ou ANNULER pour ne pas les modifier." "ou ANNULER pour ne pas les modifier."
#: src/slic3r/GUI/DoubleSlider.cpp:1917
msgid ""
"Select YES if you want to delete all saved tool changes, \n"
"NO if you want all tool changes switch to color changes, \n"
"or CANCEL to leave it unchanged."
msgstr ""
"Sélectionnez OUI si vous souhaitez supprimer tous les changements d'outil enregistrées, \n"
"NON si vous souhaitez que tous les changements d'outil soient remplacés par des modifications de couleur, \n"
"ou ANNULER pour ne pas les modifier."
#: src/slic3r/GUI/Selection.cpp:146 #: src/slic3r/GUI/Selection.cpp:146
msgid "Selection-Add" msgid "Selection-Add"
msgstr "Sélection-Ajouter" msgstr "Sélection-Ajouter"
@ -7745,6 +7780,14 @@ msgstr "L'objet sélectionné ne peut être scindé car il contient plus d'un vo
msgid "The selected object couldn't be split because it contains only one part." msgid "The selected object couldn't be split because it contains only one part."
msgstr "L'objet sélectionné n'a pu être scindé car il ne contient qu'une seule pièce." msgstr "L'objet sélectionné n'a pu être scindé car il ne contient qu'une seule pièce."
#: src/slic3r/GUI/MainFrame.cpp:432
msgid ""
"The selected project is no longer available.\n"
"Do you want to remove it from the recent projects list ?"
msgstr ""
"Le projet sélectionné n'est plus disponible.\n"
"Voulez-vous le retirer de la liste des projets récents ?"
#: src/slic3r/GUI/MainFrame.cpp:422 #: src/slic3r/GUI/MainFrame.cpp:422
msgid "The selected project is no more available" msgid "The selected project is no more available"
msgstr "Le projet sélectionné n'est plus disponible" msgstr "Le projet sélectionné n'est plus disponible"
@ -8092,6 +8135,10 @@ msgstr "Cette valeur est la hauteur de couche imprimable minimum pour cet extrud
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed." msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "Ceci est généralement provoqué par de petites extrusions négligeables ou par un modèle défectueux. Essayez de réparer le modèle ou de changer son orientation sur le lit." msgstr "Ceci est généralement provoqué par de petites extrusions négligeables ou par un modèle défectueux. Essayez de réparer le modèle ou de changer son orientation sur le lit."
#: src/libslic3r/GCode.cpp:639
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "Ceci est généralement provoqué par de petites extrusions négligeables ou par un modèle défectueux. Essayez de réparer le modèle ou de changer son orientation sur le lit."
#: src/libslic3r/PrintConfig.cpp:2215 #: src/libslic3r/PrintConfig.cpp:2215
msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools." msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools."
msgstr "Cette matrice décrit les volumes (en millimètres cube) nécessaires pour purger le nouveau filament dans la tour de nettoyage pour une paire d'outils donnée." msgstr "Cette matrice décrit les volumes (en millimètres cube) nécessaires pour purger le nouveau filament dans la tour de nettoyage pour une paire d'outils donnée."
@ -8233,6 +8280,10 @@ msgstr "Vers les objets"
msgid "To parts" msgid "To parts"
msgstr "Vers les parties" msgstr "Vers les parties"
#: src/slic3r/GUI/Tab.cpp:1756
msgid "To use a custom CA file, please import your CA file into Certificate Store / Keychain."
msgstr "Pour utiliser un fichier CA personnalisé, veuillez importer votre fichier CA dans le Magasin de Certificats / Trousseau."
#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263
#, c-format #, c-format
msgid "Toggle %c axis mirroring" msgid "Toggle %c axis mirroring"

View file

@ -5,7 +5,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.8.7.1\n" "X-Generator: Poedit 2.3\n"
"Project-Id-Version: \n" "Project-Id-Version: \n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: \n" "PO-Revision-Date: \n"
@ -1561,6 +1561,10 @@ msgstr "Cubico"
msgid "Current mode is %s" msgid "Current mode is %s"
msgstr "La modalità corrente è %s" msgstr "La modalità corrente è %s"
#: src/slic3r/GUI/Tab.cpp:959
msgid "Current preset is inherited from"
msgstr "Il preset corrente è ereditato da"
#: src/slic3r/GUI/Tab.cpp:957 #: src/slic3r/GUI/Tab.cpp:957
msgid "Current preset is inherited from the default preset." msgid "Current preset is inherited from the default preset."
msgstr "Il preset attuale è stato ereditato dal preset predefinito." msgstr "Il preset attuale è stato ereditato dal preset predefinito."
@ -2956,6 +2960,15 @@ msgstr ""
"per il tasto sinistro: indica un preset non di sistema (o non-predefinito),\n" "per il tasto sinistro: indica un preset non di sistema (o non-predefinito),\n"
"per il tasto destro: indica che le impostazioni non sono state modificate." "per il tasto destro: indica che le impostazioni non sono state modificate."
#. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3267
msgid ""
"for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: indicates that the settings hasn't been modified."
msgstr ""
"per il tasto sinistro: indica un preset non di sistema (o non-predefinito),\n"
"per il tasto destro: indica che le impostazioni non sono state modificate."
#: src/slic3r/GUI/ConfigManipulation.cpp:136 #: src/slic3r/GUI/ConfigManipulation.cpp:136
msgid "" msgid ""
"For the Wipe Tower to work with the soluble supports, the support layers\n" "For the Wipe Tower to work with the soluble supports, the support layers\n"
@ -4115,6 +4128,10 @@ msgstr "Massimo"
msgid "Max bridge length" msgid "Max bridge length"
msgstr "Lunghezza massima Bridge" msgstr "Lunghezza massima Bridge"
#: src/libslic3r/PrintConfig.cpp:2658
msgid "Max bridges on a pillar"
msgstr "Ponteggi massimi su un pilastro"
#: src/libslic3r/PrintConfig.cpp:2822 #: src/libslic3r/PrintConfig.cpp:2822
msgid "Max merge distance" msgid "Max merge distance"
msgstr "Massima distanza di unione" msgstr "Massima distanza di unione"
@ -4283,6 +4300,10 @@ msgstr "Jerk massimo Y"
msgid "Maximum jerk Z" msgid "Maximum jerk Z"
msgstr "Jerk massimo Z" msgstr "Jerk massimo Z"
#: src/libslic3r/PrintConfig.cpp:2660
msgid "Maximum number of bridges that can be placed on a pillar. Bridges hold support point pinheads and connect to pillars as small branches."
msgstr "Numero massimo di ponteggi che può essere posizionato su un pilastro. I ponteggi mantengono le capocchie dei punti di supporto e si collegano ai pilastri come piccoli rami."
#: src/libslic3r/PrintConfig.cpp:598 #: src/libslic3r/PrintConfig.cpp:598
msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit." msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit."
msgstr "Massima velocità volumetrica consentita per questo filamento. Limita la velocità volumetrica massima di una stampa alla velocità volumetrica minima del filamento e di stampa. Imposta a zero per non avere limite." msgstr "Massima velocità volumetrica consentita per questo filamento. Limita la velocità volumetrica massima di una stampa alla velocità volumetrica minima del filamento e di stampa. Imposta a zero per non avere limite."
@ -4953,6 +4974,11 @@ msgstr "di un Oggetto corrente"
msgid "Offset" msgid "Offset"
msgstr "Offset" msgstr "Offset"
#: src/slic3r/GUI/Tab.cpp:1755
#, c-format
msgid "On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain."
msgstr "Su questo sistema, %s utilizza certificati HTTPS provenienti dal sistema Certificate Store o da Keychain."
#: src/slic3r/GUI/DoubleSlider.cpp:950 #: src/slic3r/GUI/DoubleSlider.cpp:950
msgid "One layer mode" msgid "One layer mode"
msgstr "Modalità Un Layer" msgstr "Modalità Un Layer"
@ -6425,6 +6451,16 @@ msgstr ""
"NO se vuoi che tutti i cambi attrezzo passino a cambi colore,\n" "NO se vuoi che tutti i cambi attrezzo passino a cambi colore,\n"
"o ANNULLA per lasciarlo invariato." "o ANNULLA per lasciarlo invariato."
#: src/slic3r/GUI/DoubleSlider.cpp:1917
msgid ""
"Select YES if you want to delete all saved tool changes, \n"
"NO if you want all tool changes switch to color changes, \n"
"or CANCEL to leave it unchanged."
msgstr ""
"Seleziona SI se vuoi cancellare tutti i cambi attrezzo salvati,\n"
"NO se vuoi che tutti i cambi attrezzo passino a cambi colore,\n"
"o ANNULLA per lasciarlo invariato."
#: src/slic3r/GUI/Selection.cpp:146 #: src/slic3r/GUI/Selection.cpp:146
msgid "Selection-Add" msgid "Selection-Add"
msgstr "Selezione-Aggiungi" msgstr "Selezione-Aggiungi"
@ -7736,6 +7772,14 @@ msgstr "L'oggetto selezionato non può essere diviso perché contiene più di un
msgid "The selected object couldn't be split because it contains only one part." msgid "The selected object couldn't be split because it contains only one part."
msgstr "L'oggetto selezionato non può essere diviso perché contiene solo una parte." msgstr "L'oggetto selezionato non può essere diviso perché contiene solo una parte."
#: src/slic3r/GUI/MainFrame.cpp:432
msgid ""
"The selected project is no longer available.\n"
"Do you want to remove it from the recent projects list ?"
msgstr ""
"Il progetto selezionato non è più disponibile.\n"
"Vuoi rimuoverlo dall'elenco dei progetti recenti?"
#: src/slic3r/GUI/MainFrame.cpp:422 #: src/slic3r/GUI/MainFrame.cpp:422
msgid "The selected project is no more available" msgid "The selected project is no more available"
msgstr "Il progetto selezionato non è più disponibile" msgstr "Il progetto selezionato non è più disponibile"
@ -8080,6 +8124,10 @@ msgstr "Questa è l'altezza minima stampabile per questo estrusore e limita la r
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed." msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "Questo solitamente è causato da estrusioni molto piccole o da un modello difettoso. Provare a riparare il modello o cambiare il suo orientamento sul piano." msgstr "Questo solitamente è causato da estrusioni molto piccole o da un modello difettoso. Provare a riparare il modello o cambiare il suo orientamento sul piano."
#: src/libslic3r/GCode.cpp:639
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "Questo solitamente è causato da estrusioni molto piccole o da un modello difettoso. Provare a riparare il modello o cambiare il suo orientamento sul piano."
#: src/libslic3r/PrintConfig.cpp:2215 #: src/libslic3r/PrintConfig.cpp:2215
msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools." msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools."
msgstr "Questa matrice descrive il volume (in millimetri cubici) necessario per spurgare il filamento nella torre di spurgo per una qualunque coppia di attrezzi." msgstr "Questa matrice descrive il volume (in millimetri cubici) necessario per spurgare il filamento nella torre di spurgo per una qualunque coppia di attrezzi."
@ -8221,6 +8269,10 @@ msgstr "In oggetti"
msgid "To parts" msgid "To parts"
msgstr "In parti" msgstr "In parti"
#: src/slic3r/GUI/Tab.cpp:1756
msgid "To use a custom CA file, please import your CA file into Certificate Store / Keychain."
msgstr "Per utilizzare un file CA personalizzato, importa il tuo file CA sul Certificate Store / Keychain."
#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263
#, c-format #, c-format
msgid "Toggle %c axis mirroring" msgid "Toggle %c axis mirroring"

View file

@ -5,7 +5,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n" "Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 2.2.1\n" "X-Generator: Poedit 2.3\n"
"Project-Id-Version: \n" "Project-Id-Version: \n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: \n" "PO-Revision-Date: \n"
@ -1553,6 +1553,10 @@ msgstr "立方"
msgid "Current mode is %s" msgid "Current mode is %s"
msgstr "現在のモードは%sです" msgstr "現在のモードは%sです"
#: src/slic3r/GUI/Tab.cpp:959
msgid "Current preset is inherited from"
msgstr "現在のプリセット継承元"
#: src/slic3r/GUI/Tab.cpp:957 #: src/slic3r/GUI/Tab.cpp:957
msgid "Current preset is inherited from the default preset." msgid "Current preset is inherited from the default preset."
msgstr "現在の設定はデフォルト設定から継承されます。" msgstr "現在の設定はデフォルト設定から継承されます。"
@ -2941,6 +2945,15 @@ msgid ""
"for the right button: \tindicates that the settings hasn't been modified." "for the right button: \tindicates that the settings hasn't been modified."
msgstr "左ボタンの場合:システム(デフォルト)プリセットでないことを示し、右側ボタンの場合:設定が変更されていないことを示します。" msgstr "左ボタンの場合:システム(デフォルト)プリセットでないことを示し、右側ボタンの場合:設定が変更されていないことを示します。"
#. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3267
msgid ""
"for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: indicates that the settings hasn't been modified."
msgstr ""
"左ボタンの場合:システム(デフォルト)プリセットでないことを示し、\n"
"右側ボタンの場合:設定が変更されていないことを示します。"
#: src/slic3r/GUI/ConfigManipulation.cpp:136 #: src/slic3r/GUI/ConfigManipulation.cpp:136
msgid "" msgid ""
"For the Wipe Tower to work with the soluble supports, the support layers\n" "For the Wipe Tower to work with the soluble supports, the support layers\n"
@ -3571,7 +3584,9 @@ msgstr "設定が現在の設定グループのシステム(デフォルト)
msgid "" msgid ""
"indicates that the settings were changed and are not equal to the last saved preset for the current option group.\n" "indicates that the settings were changed and are not equal to the last saved preset for the current option group.\n"
"Click the BACK ARROW icon to reset all settings for the current option group to the last saved preset." "Click the BACK ARROW icon to reset all settings for the current option group to the last saved preset."
msgstr "設定が変更され、現在のオプショングループに最後に保存されたプリセットと等しくないことを示します。戻る矢印アイコンをクリックして、現在のオプショングループのすべての設定を最後に保存されたプリセットに戻します。" msgstr ""
"設定が変更され、現在のオプショングループに最後に保存されたプリセットと等しくないことを示します。\n"
"戻る矢印アイコンをクリックして、現在のオプショングループのすべての設定を最後に保存されたプリセットに戻します。"
#: src/slic3r/GUI/ConfigManipulation.cpp:211 #: src/slic3r/GUI/ConfigManipulation.cpp:211
#: src/slic3r/GUI/GUI_ObjectList.cpp:35 src/slic3r/GUI/GUI_ObjectList.cpp:96 #: src/slic3r/GUI/GUI_ObjectList.cpp:35 src/slic3r/GUI/GUI_ObjectList.cpp:96
@ -4100,6 +4115,10 @@ msgstr "最大"
msgid "Max bridge length" msgid "Max bridge length"
msgstr "最長ブリッジ長さ" msgstr "最長ブリッジ長さ"
#: src/libslic3r/PrintConfig.cpp:2658
msgid "Max bridges on a pillar"
msgstr "柱の上の最大ブリッジ数"
#: src/libslic3r/PrintConfig.cpp:2822 #: src/libslic3r/PrintConfig.cpp:2822
msgid "Max merge distance" msgid "Max merge distance"
msgstr "最大結合距離" msgstr "最大結合距離"
@ -4268,6 +4287,10 @@ msgstr "Yの最大ジャーク"
msgid "Maximum jerk Z" msgid "Maximum jerk Z"
msgstr "Zの最大ジャーク" msgstr "Zの最大ジャーク"
#: src/libslic3r/PrintConfig.cpp:2660
msgid "Maximum number of bridges that can be placed on a pillar. Bridges hold support point pinheads and connect to pillars as small branches."
msgstr "柱の上に置くことができるブリッジの最大数。 ブリッジはサポートポイントのピンヘッドを保持し、小さな枝として柱に接続します。"
#: src/libslic3r/PrintConfig.cpp:598 #: src/libslic3r/PrintConfig.cpp:598
msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit." msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit."
msgstr "このフィラメントに許容される最大体積押出し速度。プリントの最大体積押出し速度を、プリントとフィラメントの体積押出し速度の最小値にに制限します。 制限なしに設定するにはゼロを入力します。" msgstr "このフィラメントに許容される最大体積押出し速度。プリントの最大体積押出し速度を、プリントとフィラメントの体積押出し速度の最小値にに制限します。 制限なしに設定するにはゼロを入力します。"
@ -4922,6 +4945,11 @@ msgstr "現在のオブジェクトの"
msgid "Offset" msgid "Offset"
msgstr "オフセット" msgstr "オフセット"
#: src/slic3r/GUI/Tab.cpp:1755
#, c-format
msgid "On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain."
msgstr "このシステムでは、%sはシステムの証明書ストアまたはキーチェーンからのHTTPS証明書を使用します。"
#: src/slic3r/GUI/DoubleSlider.cpp:950 #: src/slic3r/GUI/DoubleSlider.cpp:950
msgid "One layer mode" msgid "One layer mode"
msgstr "1レイヤーモード" msgstr "1レイヤーモード"
@ -6391,6 +6419,16 @@ msgstr ""
"すべてのツールの変更を色の変更に切り替えたい場合は「いいえ」、\n" "すべてのツールの変更を色の変更に切り替えたい場合は「いいえ」、\n"
"または「キャンセル」で変更せずにそのままにします" "または「キャンセル」で変更せずにそのままにします"
#: src/slic3r/GUI/DoubleSlider.cpp:1917
msgid ""
"Select YES if you want to delete all saved tool changes, \n"
"NO if you want all tool changes switch to color changes, \n"
"or CANCEL to leave it unchanged."
msgstr ""
"保存したツールの変更をすべて削除する場合は、「はい」を選択します。\n"
"すべてのツールの変更を色の変更に切り替えたい場合は「いいえ」、\n"
"または「キャンセル」で変更せずにそのままにします"
#: src/slic3r/GUI/Selection.cpp:146 #: src/slic3r/GUI/Selection.cpp:146
msgid "Selection-Add" msgid "Selection-Add"
msgstr "選択-追加" msgstr "選択-追加"
@ -7696,6 +7734,14 @@ msgstr "選択したオブジェクトには複数のボリューム/マテリ
msgid "The selected object couldn't be split because it contains only one part." msgid "The selected object couldn't be split because it contains only one part."
msgstr "選択したオブジェクトには、1つのパーツしか含まれていないため、分割できませんでした。" msgstr "選択したオブジェクトには、1つのパーツしか含まれていないため、分割できませんでした。"
#: src/slic3r/GUI/MainFrame.cpp:432
msgid ""
"The selected project is no longer available.\n"
"Do you want to remove it from the recent projects list ?"
msgstr ""
"選択したプロジェクトは使用できなくなりました。\n"
"最近のプロジェクトリストから削除しますか?"
#: src/slic3r/GUI/MainFrame.cpp:422 #: src/slic3r/GUI/MainFrame.cpp:422
msgid "The selected project is no more available" msgid "The selected project is no more available"
msgstr "選択したプロジェクトはもう利用できません" msgstr "選択したプロジェクトはもう利用できません"
@ -8040,6 +8086,10 @@ msgstr "このエクストルーダーの最小プリント可能なレイヤー
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed." msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "これは通常、無視できるほど少量の押出量またはモデルの欠陥が原因です。 ベッド上のモデルの修復または向きを再配置してみてください。" msgstr "これは通常、無視できるほど少量の押出量またはモデルの欠陥が原因です。 ベッド上のモデルの修復または向きを再配置してみてください。"
#: src/libslic3r/GCode.cpp:639
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "これは通常、無視できるほど少量の押出量またはモデルの欠陥が原因です。 ベッド上のモデルの修復または向きを再配置してみてください。"
#: src/libslic3r/PrintConfig.cpp:2215 #: src/libslic3r/PrintConfig.cpp:2215
msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools." msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools."
msgstr "この行列は、任意のツールチェンジ間においてワイプタワーの新しいフィラメントをパージするために必要な体積(立方ミリメートル)を示しています。" msgstr "この行列は、任意のツールチェンジ間においてワイプタワーの新しいフィラメントをパージするために必要な体積(立方ミリメートル)を示しています。"
@ -8180,6 +8230,10 @@ msgstr "オブジェクト"
msgid "To parts" msgid "To parts"
msgstr "パーツへ" msgstr "パーツへ"
#: src/slic3r/GUI/Tab.cpp:1756
msgid "To use a custom CA file, please import your CA file into Certificate Store / Keychain."
msgstr "カスタムCAファイルを使用するには、CAファイルを証明書ストア/キーチェーンにインポートしてください。"
#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263
#, c-format #, c-format
msgid "Toggle %c axis mirroring" msgid "Toggle %c axis mirroring"

View file

@ -1207,13 +1207,13 @@ msgstr "다중 압출기 인쇄를 위해 마지막 색상 변경 데이터가
#: src/slic3r/GUI/DoubleSlider.cpp:1889 #: src/slic3r/GUI/DoubleSlider.cpp:1889
msgid "" msgid ""
"Select YES if you want to delete all saved tool changes, \n" "Select YES if you want to delete all saved tool changes,\n"
"\tNO if you want all tool changes switch to color changes, \n" "NO if you want all tool changes switch to color changes,\n"
"\tor CANCEL for do nothing" "or CANCEL for do nothing"
msgstr "" msgstr ""
"저장된 도구 변경 내용을 모두 삭제하려면 YES를 선택합니다. \n" "저장된 도구 변경 내용을 모두 삭제하려면 YES를 선택합니다.\n"
"\t아니오 모든 도구 변경 이 색상 변경으로 전환하려면 \n" "아니오 모든 도구 변경 이 색상 변경으로 전환하려면\n"
"\t또는 아무것도 하지 않는 취소" "또는 아무것도 하지 않는 취소"
#: src/slic3r/GUI/DoubleSlider.cpp:1892 #: src/slic3r/GUI/DoubleSlider.cpp:1892
msgid "Do you want to delete all saved tool changes?" msgid "Do you want to delete all saved tool changes?"
@ -5411,16 +5411,18 @@ msgstr "CA 인증서 파일 열기"
#: src/slic3r/GUI/Tab.cpp:1741 #: src/slic3r/GUI/Tab.cpp:1741
#, c-format #, c-format
msgid "" msgid ""
"HTTPS CA File:\n" "On this system, %s uses HTTPS certificates from the system Certificate "
" \tOn this system, %s uses HTTPS certificates from the system Certificate "
"Store or Keychain.\n" "Store or Keychain.\n"
" \tTo use a custom CA file, please import your CA file into Certificate " msgstr ""
"이 시스템에서 %s는 시스템 인증서 저장소나 키체인의 HTTPS 인증서를 사용 "
"합니다.\n"
#: src/slic3r/GUI/Tab.cpp:1741
msgid ""
"To use a custom CA file, please import your CA file into Certificate "
"Store / Keychain." "Store / Keychain."
msgstr "" msgstr ""
"HTTPS CA 파일:\n" "사용자 지정 CA 파일을 사용 하려면 CA 파일을 인증서 저장소/키체인에 가져"
" \t이 시스템에서 %s는 시스템 인증서 저장소나 키체인의 HTTPS 인증서를 사용 "
"합니다.\n"
" \t사용자 지정 CA 파일을 사용 하려면 CA 파일을 인증서 저장소/키체인에 가져"
"오십시오." "오십시오."
#: src/slic3r/GUI/Tab.cpp:1781 src/slic3r/GUI/Tab.cpp:2025 #: src/slic3r/GUI/Tab.cpp:1781 src/slic3r/GUI/Tab.cpp:2025
@ -5717,8 +5719,8 @@ msgstr "흰색 글머리 기호"
#. TRN Description for "WHITE BULLET" #. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3235 #: src/slic3r/GUI/Tab.cpp:3235
msgid "" msgid ""
"for the left button: \tindicates a non-system (or non-default) preset,\n" "for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: \tindicates that the settings hasn't been modified." "for the right button: indicates that the settings hasn't been modified."
msgstr "" msgstr ""
"왼쪽 단추의 경우: 비시스템(또는 기본이 아닌) 사전 설정을 나타냅니다.\n" "왼쪽 단추의 경우: 비시스템(또는 기본이 아닌) 사전 설정을 나타냅니다.\n"
"오른쪽 버튼: 설정이 수정되지 않았음을 나타냅니다." "오른쪽 버튼: 설정이 수정되지 않았음을 나타냅니다."
@ -6478,7 +6480,7 @@ msgstr "인쇄 z"
#: src/libslic3r/GCode.cpp:639 #: src/libslic3r/GCode.cpp:639
msgid "" msgid ""
"This is usually caused by negligibly small extrusions or by a faulty model. " "This is usually caused by negligibly small extrusions or by a faulty model. "
"Try to repair the model or change its orientation on the bed." "Try to repair the model or change its orientation on the bed."
msgstr "" msgstr ""
"이는 일반적으로 무시할 수 있는 작은 돌출 또는 결함이 있는 모델에 의해 발생합" "이는 일반적으로 무시할 수 있는 작은 돌출 또는 결함이 있는 모델에 의해 발생합"
"니다. 모델을 수리하거나 배드에서 방향을 변경하십시오." "니다. 모델을 수리하거나 배드에서 방향을 변경하십시오."

View file

@ -1223,9 +1223,9 @@ msgstr "Weet u zeker dat u wilt doorgaan?"
#: src/slic3r/GUI/DoubleSlider.cpp:1915 #: src/slic3r/GUI/DoubleSlider.cpp:1915
msgid "" msgid ""
"Select YES if you want to delete all saved tool changes, \n" "Select YES if you want to delete all saved tool changes,\n"
"\tNO if you want all tool changes switch to color changes, \n" "NO if you want all tool changes switch to color changes,\n"
"\tor CANCEL to leave it unchanged" "or CANCEL to leave it unchanged"
msgstr "" msgstr ""
"Selecteer JA als u alle opgeslagen toolwisselingen wilt verwijdere,\n" "Selecteer JA als u alle opgeslagen toolwisselingen wilt verwijdere,\n"
"Selecteer NEE als u alle toolwisselingen wil omzetten in kleurwisselingen\n" "Selecteer NEE als u alle toolwisselingen wil omzetten in kleurwisselingen\n"
@ -5264,11 +5264,9 @@ msgstr "Huidige preset is gebaseerd op de standaard preset."
#: src/slic3r/GUI/Tab.cpp:962 #: src/slic3r/GUI/Tab.cpp:962
#, c-format #, c-format
msgid "" msgid ""
"Current preset is inherited from:\n" "Current preset is inherited from"
"\t%s"
msgstr "" msgstr ""
"Huidige preset is gebaseerd op:\n" "Huidige preset is gebaseerd op"
"\t%s"
#: src/slic3r/GUI/Tab.cpp:966 #: src/slic3r/GUI/Tab.cpp:966
msgid "It can't be deleted or modified." msgid "It can't be deleted or modified."
@ -5544,16 +5542,18 @@ msgstr "Open een CA-certificaatbestand"
#: src/slic3r/GUI/Tab.cpp:1759 #: src/slic3r/GUI/Tab.cpp:1759
#, c-format #, c-format
msgid "" msgid ""
"HTTPS CA File:\n" "On this system, %s uses HTTPS certificates from the system Certificate "
" \tOn this system, %s uses HTTPS certificates from the system Certificate " "Store or Keychain."
"Store or Keychain.\n" msgstr ""
" \tTo use a custom CA file, please import your CA file into Certificate " "%s gebruikt op dit systeem HTTPS-certificaten van de Certificate Store "
"of Keychain."
#: src/slic3r/GUI/Tab.cpp:1759
msgid ""
"To use a custom CA file, please import your CA file into Certificate "
"Store / Keychain." "Store / Keychain."
msgstr "" msgstr ""
"HTTPS-CA-bestand:\n" "Om een aangepast CA-bestand te gebruiken moet uw CA-bestand in de "
" \t%s gebruikt op dit systeem HTTPS-certificaten van de Certificate Store "
"of Keychain.\n"
" \tOm een aangepast CA-bestand te gebruiken moet uw CA-bestand in de "
"Certificate Store of Keychain geïmporteerd worden." "Certificate Store of Keychain geïmporteerd worden."
#: src/slic3r/GUI/Tab.cpp:1799 src/slic3r/GUI/Tab.cpp:2043 #: src/slic3r/GUI/Tab.cpp:1799 src/slic3r/GUI/Tab.cpp:2043
@ -5855,11 +5855,11 @@ msgstr "Wit bolletje"
#. TRN Description for "WHITE BULLET" #. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3255 #: src/slic3r/GUI/Tab.cpp:3255
msgid "" msgid ""
"for the left button: \tindicates a non-system (or non-default) preset,\n" "for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: \tindicates that the settings hasn't been modified." "for the right button: indicates that the settings hasn't been modified."
msgstr "" msgstr ""
"linker knop: \tgeeft een niet-systeempreset aan,\n" "linker knop: geeft een niet-systeempreset aan,\n"
"rechter knop: \tgeeft aan dat de instelling niet veranderd is." "rechter knop: geeft aan dat de instelling niet veranderd is."
#: src/slic3r/GUI/Tab.cpp:3258 #: src/slic3r/GUI/Tab.cpp:3258
msgid "BACK ARROW" msgid "BACK ARROW"
@ -6623,7 +6623,7 @@ msgstr "Print Z"
#: src/libslic3r/GCode.cpp:639 #: src/libslic3r/GCode.cpp:639
msgid "" msgid ""
"This is usually caused by negligibly small extrusions or by a faulty model. " "This is usually caused by negligibly small extrusions or by a faulty model. "
"Try to repair the model or change its orientation on the bed." "Try to repair the model or change its orientation on the bed."
msgstr "" msgstr ""
"Dit komt meestal voor bij verwaarloosbare extrusiehoeveelheden of door een " "Dit komt meestal voor bij verwaarloosbare extrusiehoeveelheden of door een "
"foutief model. Probeer het model te repareren of verander de oriëntatie." "foutief model. Probeer het model te repareren of verander de oriëntatie."

View file

@ -5,7 +5,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || n%10 == 1 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 12 && n%100 <= 14)) ? 2 : 3);\n" "Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || n%10 == 1 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 12 && n%100 <= 14)) ? 2 : 3);\n"
"X-Generator: Poedit 2.2.1\n" "X-Generator: Poedit 2.3\n"
"Project-Id-Version: \n" "Project-Id-Version: \n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: \n" "PO-Revision-Date: \n"
@ -1032,7 +1032,7 @@ msgstr "Mosty objętościowe"
#: src/slic3r/GUI/Plater.cpp:534 src/slic3r/GUI/Tab.cpp:1117 #: src/slic3r/GUI/Plater.cpp:534 src/slic3r/GUI/Tab.cpp:1117
msgid "Brim" msgid "Brim"
msgstr "Brim (obramowanie)" msgstr "Brim"
#: src/libslic3r/PrintConfig.cpp:244 #: src/libslic3r/PrintConfig.cpp:244
msgid "Brim width" msgid "Brim width"
@ -1561,6 +1561,10 @@ msgstr "Sześcienny"
msgid "Current mode is %s" msgid "Current mode is %s"
msgstr "Obecny tryb to %s" msgstr "Obecny tryb to %s"
#: src/slic3r/GUI/Tab.cpp:959
msgid "Current preset is inherited from"
msgstr "Obecny zestaw ustawień jest dziedziczony z"
#: src/slic3r/GUI/Tab.cpp:957 #: src/slic3r/GUI/Tab.cpp:957
msgid "Current preset is inherited from the default preset." msgid "Current preset is inherited from the default preset."
msgstr "Obecny zestaw ustawień jest dziedziczony z zestawu domyślnego." msgstr "Obecny zestaw ustawień jest dziedziczony z zestawu domyślnego."
@ -2956,6 +2960,15 @@ msgstr ""
"dla lewego przycisku: wskazuje na niesystemowy (lub inny niż domyślny) zestaw ustawień,\n" "dla lewego przycisku: wskazuje na niesystemowy (lub inny niż domyślny) zestaw ustawień,\n"
"dla prawego przycisku: wskazuje, że ustawienia nie zostały zmodyfikowane." "dla prawego przycisku: wskazuje, że ustawienia nie zostały zmodyfikowane."
#. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3267
msgid ""
"for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: indicates that the settings hasn't been modified."
msgstr ""
"dla lewego przycisku: wskazuje na niesystemowy (lub inny niż domyślny) zestaw ustawień,\n"
"dla prawego przycisku: wskazuje, że ustawienia nie zostały zmodyfikowane."
#: src/slic3r/GUI/ConfigManipulation.cpp:136 #: src/slic3r/GUI/ConfigManipulation.cpp:136
msgid "" msgid ""
"For the Wipe Tower to work with the soluble supports, the support layers\n" "For the Wipe Tower to work with the soluble supports, the support layers\n"
@ -3572,7 +3585,7 @@ msgid ""
"indicates that some settings were changed and are not equal to the system (or default) values for the current option group.\n" "indicates that some settings were changed and are not equal to the system (or default) values for the current option group.\n"
"Click the UNLOCKED LOCK icon to reset all settings for current option group to the system (or default) values." "Click the UNLOCKED LOCK icon to reset all settings for current option group to the system (or default) values."
msgstr "" msgstr ""
"oznacza, że niektóre ustawienia zostały zmodyfikowane i nie odpowiadają wartościom systemowym (lub domyślnym) w obecnej grupie opcji. \n" "oznacza, że niektóre ustawienia zostały zmodyfikowane i nie odpowiadają wartościom systemowym (lub domyślnym) w obecnej grupie opcji.\n"
"Kliknij ikonę OTWARTEJ KŁÓDKI, aby zresetować wszystkie ustawienia obecnej grupy ustawień do wartości systemowych (lub domyślnych)." "Kliknij ikonę OTWARTEJ KŁÓDKI, aby zresetować wszystkie ustawienia obecnej grupy ustawień do wartości systemowych (lub domyślnych)."
#. TRN Description for "LOCKED LOCK" #. TRN Description for "LOCKED LOCK"
@ -4116,6 +4129,10 @@ msgstr "Max"
msgid "Max bridge length" msgid "Max bridge length"
msgstr "Maksymalna długość mostu" msgstr "Maksymalna długość mostu"
#: src/libslic3r/PrintConfig.cpp:2658
msgid "Max bridges on a pillar"
msgstr "Maks. liczba mostków na słupku"
#: src/libslic3r/PrintConfig.cpp:2822 #: src/libslic3r/PrintConfig.cpp:2822
msgid "Max merge distance" msgid "Max merge distance"
msgstr "Maksymalny dystans łączenia" msgstr "Maksymalny dystans łączenia"
@ -4284,6 +4301,10 @@ msgstr "Maksymalny jerk Y"
msgid "Maximum jerk Z" msgid "Maximum jerk Z"
msgstr "Maksymalny jerk Z" msgstr "Maksymalny jerk Z"
#: src/libslic3r/PrintConfig.cpp:2660
msgid "Maximum number of bridges that can be placed on a pillar. Bridges hold support point pinheads and connect to pillars as small branches."
msgstr "Maksymalna liczba mostków, która zostanie umieszczona na słupku podpory. Mostki wspierają łączniki podpór i łączą słupki podpór."
#: src/libslic3r/PrintConfig.cpp:598 #: src/libslic3r/PrintConfig.cpp:598
msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit." msgid "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit."
msgstr "Maksymalna prędkość objętościowa dla tego filamentu. Ogranicza maksymalną prędkość objętościową do minimum objętościowej prędkości druku i filamentu. Ustaw zero aby usunąć ograniczenie." msgstr "Maksymalna prędkość objętościowa dla tego filamentu. Ogranicza maksymalną prędkość objętościową do minimum objętościowej prędkości druku i filamentu. Ustaw zero aby usunąć ograniczenie."
@ -4954,6 +4975,11 @@ msgstr "obecnego Modelu"
msgid "Offset" msgid "Offset"
msgstr "Offset" msgstr "Offset"
#: src/slic3r/GUI/Tab.cpp:1755
#, c-format
msgid "On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain."
msgstr "W tym systemie, %s używa certyfikatu HTTPS z magazynu systemowego (Certificate Store) lub Keychain."
#: src/slic3r/GUI/DoubleSlider.cpp:950 #: src/slic3r/GUI/DoubleSlider.cpp:950
msgid "One layer mode" msgid "One layer mode"
msgstr "Tryb jednej warstwy" msgstr "Tryb jednej warstwy"
@ -6430,6 +6456,16 @@ msgstr ""
"NIE, jeśli chcesz przełączyć zmiany narzędzi na zmiany koloru lub\n" "NIE, jeśli chcesz przełączyć zmiany narzędzi na zmiany koloru lub\n"
"ANULUJ, aby pozostawić bez zmian." "ANULUJ, aby pozostawić bez zmian."
#: src/slic3r/GUI/DoubleSlider.cpp:1917
msgid ""
"Select YES if you want to delete all saved tool changes, \n"
"NO if you want all tool changes switch to color changes, \n"
"or CANCEL to leave it unchanged."
msgstr ""
"Wybierz TAK, jeśli chcesz usunąć wszystkie zapisane zmiany narzędzi,\n"
"NIE, jeśli chcesz przełączyć zmiany narzędzi na zmiany koloru lub\n"
"ANULUJ, aby pozostawić bez zmian."
#: src/slic3r/GUI/Selection.cpp:146 #: src/slic3r/GUI/Selection.cpp:146
msgid "Selection-Add" msgid "Selection-Add"
msgstr "Zaznaczenie-Dodaj" msgstr "Zaznaczenie-Dodaj"
@ -7738,6 +7774,14 @@ msgstr "Wybrany model nie może być podzielony ponieważ składa się z więcej
msgid "The selected object couldn't be split because it contains only one part." msgid "The selected object couldn't be split because it contains only one part."
msgstr "Wybrany model nie może być rozdzielony ponieważ zawiera tylko jedną część." msgstr "Wybrany model nie może być rozdzielony ponieważ zawiera tylko jedną część."
#: src/slic3r/GUI/MainFrame.cpp:432
msgid ""
"The selected project is no longer available.\n"
"Do you want to remove it from the recent projects list ?"
msgstr ""
"Wybrany obiekt nie jest już dostępny.\n"
"Czy chcesz usunąć go z listy niedawno używanych projektów?"
#: src/slic3r/GUI/MainFrame.cpp:422 #: src/slic3r/GUI/MainFrame.cpp:422
msgid "The selected project is no more available" msgid "The selected project is no more available"
msgstr "Wybrany projekt nie jest dostępny" msgstr "Wybrany projekt nie jest dostępny"
@ -8083,6 +8127,10 @@ msgstr "To jest najniższa możliwa do wydrukowania wysokość warstwy dla tego
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed." msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "Dzieje się to zazwyczaj z powodu zbyt małych odcinków ekstruzji (są one pomijane) lub uszkodzenia modelu. Spróbuj naprawić model lub zmienić jego orientację na stole." msgstr "Dzieje się to zazwyczaj z powodu zbyt małych odcinków ekstruzji (są one pomijane) lub uszkodzenia modelu. Spróbuj naprawić model lub zmienić jego orientację na stole."
#: src/libslic3r/GCode.cpp:639
msgid "This is usually caused by negligibly small extrusions or by a faulty model. Try to repair the model or change its orientation on the bed."
msgstr "Dzieje się to zazwyczaj z powodu zbyt małych odcinków ekstruzji (są one pomijane) lub uszkodzenia modelu. Spróbuj naprawić model lub zmienić jego orientację na stole."
#: src/libslic3r/PrintConfig.cpp:2215 #: src/libslic3r/PrintConfig.cpp:2215
msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools." msgid "This matrix describes volumes (in cubic milimetres) required to purge the new filament on the wipe tower for any given pair of tools."
msgstr "Ta formuła określa objętość (w milimetrach sześciennych) wymaganą do wyczyszczenia filamentu na wieży czyszczącej dla danej pary narzędzi (filamentów)." msgstr "Ta formuła określa objętość (w milimetrach sześciennych) wymaganą do wyczyszczenia filamentu na wieży czyszczącej dla danej pary narzędzi (filamentów)."
@ -8224,6 +8272,10 @@ msgstr "Do modeli"
msgid "To parts" msgid "To parts"
msgstr "Na części" msgstr "Na części"
#: src/slic3r/GUI/Tab.cpp:1756
msgid "To use a custom CA file, please import your CA file into Certificate Store / Keychain."
msgstr "Aby użyć własnego certyfikatu, zaimportuj plik do Certificate Store / Keychain."
#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:263
#, c-format #, c-format
msgid "Toggle %c axis mirroring" msgid "Toggle %c axis mirroring"

View file

@ -4196,11 +4196,9 @@ msgstr "Predefinição atual é herdada da predefinição padrão."
#: src/slic3r/GUI/Tab.cpp:950 #: src/slic3r/GUI/Tab.cpp:950
#, c-format #, c-format
msgid "" msgid ""
"Current preset is inherited from:\n" "Current preset is inherited from"
"\t%s"
msgstr "" msgstr ""
"Predefinição atual é herdada de:\n" "Predefinição atual é herdada de"
"\t%s"
#: src/slic3r/GUI/Tab.cpp:954 #: src/slic3r/GUI/Tab.cpp:954
msgid "It can't be deleted or modified." msgid "It can't be deleted or modified."
@ -4472,16 +4470,18 @@ msgstr "Abra o arquivo de certificado da CA"
#: src/slic3r/GUI/Tab.cpp:1962 #: src/slic3r/GUI/Tab.cpp:1962
#, c-format #, c-format
msgid "" msgid ""
"HTTPS CA File:\n" "On this system, %s uses HTTPS certificates from the system Certificate "
" \tOn this system, %s uses HTTPS certificates from the system Certificate " "Store or Keychain."
"Store or Keychain.\n" msgstr ""
" \tTo use a custom CA file, please import your CA file into Certificate " "Neste sistema, %s usa certificados HTTPS do sistema Certificate Store "
"ou keychain."
#: src/slic3r/GUI/Tab.cpp:1962
msgid ""
"To use a custom CA file, please import your CA file into Certificate "
"Store / Keychain." "Store / Keychain."
msgstr "" msgstr ""
"Arquivo HTTPS CA:\n" "Para usar um arquivo de CA personalizado, importe seu arquivo de CA "
" \tNeste sistema, %s usa certificados HTTPS do sistema Certificate Store "
"ou keychain.\n"
" \tPara usar um arquivo de CA personalizado, importe seu arquivo de CA "
"para o repositório de certificados/chaveiro." "para o repositório de certificados/chaveiro."
#: src/slic3r/GUI/Tab.cpp:2002 src/slic3r/GUI/Tab.cpp:2243 #: src/slic3r/GUI/Tab.cpp:2002 src/slic3r/GUI/Tab.cpp:2243
@ -4778,12 +4778,12 @@ msgstr "PONTO BRANCO"
#. TRN Description for "WHITE BULLET" #. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3427 #: src/slic3r/GUI/Tab.cpp:3427
msgid "" msgid ""
"for the left button: \tindicates a non-system (or non-default) preset,\n" "for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: \tindicates that the settings hasn't been modified." "for the right button: indicates that the settings hasn't been modified."
msgstr "" msgstr ""
"para o botão esquerdo: \t indica uma predefinição que não é do sistema (ou " "para o botão esquerdo: indica uma predefinição que não é do sistema (ou "
"não-padrão),\n" "não-padrão),\n"
"para o botão direito: \t indica que as config. não foram modificadas." "para o botão direito: indica que as config. não foram modificadas."
#: src/slic3r/GUI/Tab.cpp:3430 #: src/slic3r/GUI/Tab.cpp:3430
msgid "BACK ARROW" msgid "BACK ARROW"

View file

@ -3679,13 +3679,15 @@ msgstr "CA sertifika dosyasını aç"
#: src/slic3r/GUI/Tab.cpp:1810 #: src/slic3r/GUI/Tab.cpp:1810
#, c-format #, c-format
msgid "" msgid ""
"HTTPS CA File:\n" "On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain."
" \tOn this system, %s uses HTTPS certificates from the system Certificate Store or Keychain.\n"
" \tTo use a custom CA file, please import your CA file into Certificate Store / Keychain."
msgstr "" msgstr ""
"HTTPS CA Dosyası:\n" "Bu sistemde, %s , sistem Sertifika Deposu veya Anahtarlıktan HTTPS sertifikaları kullanır."
" \tBu sistemde, %s , sistem Sertifika Deposu veya Anahtarlıktan HTTPS sertifikaları kullanır.\n"
" \tÖzel bir CA dosyası kullanmak için, lütfen CA dosyanızı Sertifika Deposu/Anahtarlık içine aktarın." #: src/slic3r/GUI/Tab.cpp:1810
msgid ""
"To use a custom CA file, please import your CA file into Certificate Store / Keychain."
msgstr ""
"Özel bir CA dosyası kullanmak için, lütfen CA dosyanızı Sertifika Deposu/Anahtarlık içine aktarın."
#: src/slic3r/GUI/Tab.cpp:1850 src/slic3r/GUI/Tab.cpp:2051 #: src/slic3r/GUI/Tab.cpp:1850 src/slic3r/GUI/Tab.cpp:2051
msgid "Size and coordinates" msgid "Size and coordinates"
@ -3948,11 +3950,11 @@ msgstr "BEYAZ NOKTA"
#. TRN Description for "WHITE BULLET" #. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3129 #: src/slic3r/GUI/Tab.cpp:3129
msgid "" msgid ""
"for the left button: \tindicates a non-system preset,\n" "for the left button: indicates a non-system preset,\n"
"for the right button: \tindicates that the settings hasn't been modified." "for the right button: indicates that the settings hasn't been modified."
msgstr "" msgstr ""
"sol tuş için: \tsistem dışı bir ön ayarı gösterir,\n" "sol tuş için: sistem dışı bir ön ayarı gösterir,\n"
"sağ tuş için: \tayarların değiştirilmediğini gösterir." "sağ tuş için: ayarların değiştirilmediğini gösterir."
#: src/slic3r/GUI/Tab.cpp:3103 #: src/slic3r/GUI/Tab.cpp:3103
msgid "BACK ARROW" msgid "BACK ARROW"

View file

@ -4106,11 +4106,9 @@ msgstr "当前预设从默认预设继承。"
#: src/slic3r/GUI/Tab.cpp:947 #: src/slic3r/GUI/Tab.cpp:947
#, c-format #, c-format
msgid "" msgid ""
"Current preset is inherited from:\n" "Current preset is inherited from"
"\t%s"
msgstr "" msgstr ""
"当前预设继承自:\n" "当前预设继承自"
"\t%s"
#: src/slic3r/GUI/Tab.cpp:951 #: src/slic3r/GUI/Tab.cpp:951
msgid "It can't be deleted or modified." msgid "It can't be deleted or modified."
@ -4375,15 +4373,17 @@ msgstr "打开 CA 证书文件"
#: src/slic3r/GUI/Tab.cpp:1959 #: src/slic3r/GUI/Tab.cpp:1959
#, c-format #, c-format
msgid "" msgid ""
"HTTPS CA File:\n" "On this system, %s uses HTTPS certificates from the system Certificate "
" \tOn this system, %s uses HTTPS certificates from the system Certificate " "Store or Keychain."
"Store or Keychain.\n" msgstr ""
" \tTo use a custom CA file, please import your CA file into Certificate " "在此系统上,%s 使用来自系统证书存储或钥匙串的 HTTPS 证书。"
#: src/slic3r/GUI/Tab.cpp:1959
msgid ""
"To use a custom CA file, please import your CA file into Certificate "
"Store / Keychain." "Store / Keychain."
msgstr "" msgstr ""
"HTTPS CA 文件:\n" "要使用自定义 CA 文件,请将 CA 文件导入证书存储/钥匙串。"
" \t在此系统上,%s 使用来自系统证书存储或钥匙串的 HTTPS 证书。\n"
" \t要使用自定义 CA 文件,请将 CA 文件导入证书存储/钥匙串。"
#: src/slic3r/GUI/Tab.cpp:1999 src/slic3r/GUI/Tab.cpp:2240 #: src/slic3r/GUI/Tab.cpp:1999 src/slic3r/GUI/Tab.cpp:2240
msgid "Size and coordinates" msgid "Size and coordinates"
@ -4671,8 +4671,8 @@ msgstr "白色子弹"
#. TRN Description for "WHITE BULLET" #. TRN Description for "WHITE BULLET"
#: src/slic3r/GUI/Tab.cpp:3424 #: src/slic3r/GUI/Tab.cpp:3424
msgid "" msgid ""
"for the left button: \tindicates a non-system (or non-default) preset,\n" "for the left button: indicates a non-system (or non-default) preset,\n"
"for the right button: \tindicates that the settings hasn't been modified." "for the right button: indicates that the settings hasn't been modified."
msgstr "" msgstr ""
"对于左侧按钮:指示非系统(或非默认)预设,\n" "对于左侧按钮:指示非系统(或非默认)预设,\n"
"对于右侧按钮:指示设置尚未修改。" "对于右侧按钮:指示设置尚未修改。"

View file

@ -3049,8 +3049,8 @@ msgid "It's a system preset."
msgstr "這是一個系統預設。" msgstr "這是一個系統預設。"
#: src/slic3r/GUI/Tab.cpp:860 #: src/slic3r/GUI/Tab.cpp:860
msgid "Current preset is inherited from " msgid "Current preset is inherited from"
msgstr "當前預設繼承自 " msgstr "當前預設繼承自"
#: src/slic3r/GUI/Tab.cpp:865 #: src/slic3r/GUI/Tab.cpp:865
msgid "It can't be deleted or modified. " msgid "It can't be deleted or modified. "
@ -3391,16 +3391,19 @@ msgid "Open CA certificate file"
msgstr "打開 CA 證書文件" msgstr "打開 CA 證書文件"
#: src/slic3r/GUI/Tab.cpp:1725 #: src/slic3r/GUI/Tab.cpp:1725
#, c-format
msgid "" msgid ""
"HTTPS CA File:\n" "On this system, %s uses HTTPS certificates from the system Certificate "
"\tOn this system, Slic3r uses HTTPS certificates from the system Certificate " "Store or Keychain."
"Store or Keychain.\n" msgstr ""
"\tTo use a custom CA file, please import your CA file into Certificate " "在此係統上, %s 使用來自系統證書存儲或鑰匙串的 https 證書。"
#: src/slic3r/GUI/Tab.cpp:1725
msgid ""
"To use a custom CA file, please import your CA file into Certificate "
"Store / Keychain." "Store / Keychain."
msgstr "" msgstr ""
"HTTPS CA 文件:\n" "要使用自定義 CA 文件, 請將 CA 文件導入到證書存儲/鑰匙串。"
"\t在此係統上, Slic3r 使用來自系統證書存儲或鑰匙串的 https 證書。\n"
"\t要使用自定義 CA 文件, 請將 CA 文件導入到證書存儲/鑰匙串。"
#: src/slic3r/GUI/Tab.cpp:1763 src/slic3r/GUI/Tab.cpp:1964 #: src/slic3r/GUI/Tab.cpp:1763 src/slic3r/GUI/Tab.cpp:1964
msgid "Size and coordinates" msgid "Size and coordinates"
@ -3664,11 +3667,11 @@ msgstr ""
#: src/slic3r/GUI/Tab.cpp:2998 #: src/slic3r/GUI/Tab.cpp:2998
msgid "" msgid ""
"WHITE BULLET;for the left button: \tindicates a non-system preset,\n" "WHITE BULLET;for the left button: indicates a non-system preset,\n"
"for the right button: \tindicates that the settings hasn't been modified." "for the right button: indicates that the settings hasn't been modified."
msgstr "" msgstr ""
"白色彈頭; 對於左側按鈕: \t表示非系統預設,\n" "白色彈頭; 對於左側按鈕: 表示非系統預設,\n"
"對於右側按鈕: \t表示設置尚未被修改。" "對於右側按鈕: 表示設置尚未被修改。"
#: src/slic3r/GUI/Tab.cpp:3002 #: src/slic3r/GUI/Tab.cpp:3002
msgid "" msgid ""

View file

@ -0,0 +1,384 @@
# generated by PrusaSlicer 2.1.1+win64 on 2020-02-25 at 01:51:21 UTC
[vendor]
# Vendor name will be shown by the Config Wizard.
name = Lulzbot
config_version = 0.0.1
config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Lulzbot/
[printer_model:MINI_AERO]
name = Mini Aero
variants = 0.5
technology = FFF
#bed_model = mini_bed.stl
#bed_texture = mini.svg
default_materials = ColorFabb PLA-PHA @lulzbot;PrintedSolid Jesse PLA @lulzbot
[printer_model:TAZ6_AERO]
name = Taz6 Aero
variants = 0.5
technology = FFF
default_materials = ColorFabb PLA-PHA @lulzbot;PrintedSolid Jesse PLA @lulzbot
[print:0.3mm @lulzbot]
avoid_crossing_perimeters = 0
bottom_fill_pattern = rectilinear
bottom_solid_layers = 3
bridge_acceleration = 500
bridge_angle = 0
bridge_flow_ratio = 1
bridge_speed = 30
brim_width = 0
clip_multipart_objects = 0
compatible_printers =
compatible_printers_condition =
complete_objects = 0
default_acceleration = 500
dont_support_bridges = 1
elefant_foot_compensation = 0
ensure_vertical_shell_thickness = 0
external_perimeter_extrusion_width = 0.56
external_perimeter_speed = 50%
external_perimeters_first = 0
extra_perimeters = 1
extruder_clearance_height = 20
extruder_clearance_radius = 20
extrusion_width = 0.56
fill_angle = 45
fill_density = 20%
fill_pattern = gyroid
first_layer_acceleration = 500
first_layer_extrusion_width = 0.6
first_layer_height = 100%
first_layer_speed = 40%
gap_fill_speed = 20
gcode_comments = 0
gcode_label_objects = 0
infill_acceleration = 500
infill_every_layers = 1
infill_extruder = 1
infill_extrusion_width = 0.56
infill_first = 0
infill_only_where_needed = 0
infill_overlap = 25%
infill_speed = 60
inherits =
interface_shells = 0
layer_height = 0.3
max_print_speed = 80
max_volumetric_speed = 0
min_skirt_length = 0
notes =
only_retract_when_crossing_perimeters = 1
ooze_prevention = 0
output_filename_format = [printer_settings_id]_[input_filename_base]_[layer_height]_[filament_type]_[print_time].gcode
overhangs = 1
perimeter_acceleration = 500
perimeter_extruder = 1
perimeter_extrusion_width = 0.56
perimeter_speed = 60
perimeters = 3
post_process =
raft_layers = 0
resolution = 0
seam_position = nearest
single_extruder_multi_material_priming = 1
skirt_distance = 3
skirt_height = 1
skirts = 3
slice_closing_radius = 0.049
small_perimeter_speed = 15
solid_infill_below_area = 70
solid_infill_every_layers = 0
solid_infill_extruder = 1
solid_infill_extrusion_width = 0.56
solid_infill_speed = 60
spiral_vase = 0
standby_temperature_delta = -5
support_material = 0
support_material_angle = 0
support_material_auto = 1
support_material_buildplate_only = 0
support_material_contact_distance = 0.2
support_material_enforce_layers = 0
support_material_extruder = 1
support_material_extrusion_width = 0.44
support_material_interface_contact_loops = 0
support_material_interface_extruder = 1
support_material_interface_layers = 3
support_material_interface_spacing = 0
support_material_interface_speed = 100%
support_material_pattern = rectilinear
support_material_spacing = 2.5
support_material_speed = 60
support_material_synchronize_layers = 0
support_material_threshold = 0
support_material_with_sheath = 1
support_material_xy_spacing = 50%
thin_walls = 1
threads = 12
top_fill_pattern = rectilinear
top_infill_extrusion_width = 0.52
top_solid_infill_speed = 40
top_solid_layers = 3
travel_speed = 175
wipe_tower = 0
wipe_tower_bridging = 10
wipe_tower_rotation_angle = 0
wipe_tower_width = 60
wipe_tower_x = 180
wipe_tower_y = 140
xy_size_compensation = 0
[filament:ColorFabb PLA-PHA @lulzbot]
filament_vendor = ColorFabb
bed_temperature = 60
bridge_fan_speed = 100
compatible_printers =
compatible_printers_condition =
compatible_prints =
compatible_prints_condition =
cooling = 1
disable_fan_first_layers = 3
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
extrusion_multiplier = 1
fan_always_on = 0
fan_below_layer_time = 60
filament_colour = #29B2B2
filament_cooling_final_speed = 3.4
filament_cooling_initial_speed = 2.2
filament_cooling_moves = 4
filament_cost = 0
filament_density = 1.25
filament_deretract_speed = nil
filament_diameter = 2.85
filament_load_time = 0
filament_loading_speed = 28
filament_loading_speed_start = 3
filament_max_volumetric_speed = 0
filament_minimal_purge_on_wipe_tower = 15
filament_notes = ""
filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
filament_retract_before_travel = nil
filament_retract_before_wipe = nil
filament_retract_layer_change = nil
filament_retract_length = nil
filament_retract_lift = nil
filament_retract_lift_above = nil
filament_retract_lift_below = nil
filament_retract_restart_extra = nil
filament_retract_speed = nil
filament_soluble = 0
filament_toolchange_delay = 0
filament_type = PLA
filament_unload_time = 0
filament_unloading_speed = 90
filament_unloading_speed_start = 100
filament_wipe = nil
first_layer_bed_temperature = 60
first_layer_temperature = 200
inherits =
max_fan_speed = 100
min_fan_speed = 35
min_print_speed = 10
slowdown_below_layer_time = 5
start_filament_gcode = "; Filament gcode\n"
temperature = 200
[filament:PrintedSolid Jesse PLA @lulzbot]
filament_vendor = PrintedSolid
bed_temperature = 60
bridge_fan_speed = 100
compatible_printers =
compatible_printers_condition =
compatible_prints =
compatible_prints_condition =
cooling = 1
disable_fan_first_layers = 3
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
extrusion_multiplier = 1
fan_always_on = 0
fan_below_layer_time = 60
filament_colour = #29B2B2
filament_cooling_final_speed = 3.4
filament_cooling_initial_speed = 2.2
filament_cooling_moves = 4
filament_cost = 27
filament_density = 1.25
filament_deretract_speed = nil
filament_diameter = 2.85
filament_load_time = 0
filament_loading_speed = 28
filament_loading_speed_start = 3
filament_max_volumetric_speed = 0
filament_minimal_purge_on_wipe_tower = 15
filament_notes = ""
filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
filament_retract_before_travel = nil
filament_retract_before_wipe = nil
filament_retract_layer_change = nil
filament_retract_length = nil
filament_retract_lift = nil
filament_retract_lift_above = nil
filament_retract_lift_below = nil
filament_retract_restart_extra = nil
filament_retract_speed = nil
filament_soluble = 0
filament_toolchange_delay = 0
filament_type = PLA
filament_unload_time = 0
filament_unloading_speed = 90
filament_unloading_speed_start = 100
filament_wipe = nil
first_layer_bed_temperature = 60
first_layer_temperature = 220
inherits =
max_fan_speed = 100
min_fan_speed = 35
min_print_speed = 10
slowdown_below_layer_time = 5
start_filament_gcode = "; Filament gcode\n"
temperature = 220
[printer:Mini Aero 0.5mm]
printer_model = MINI_AERO
printer_variant = 0.5
default_print_profile = 0.3mm @lulzbot
default_filament_profile = PrintedSolid Jesse PLA @lulzbot
bed_shape = 0x0,154x0,154x154,0x154
before_layer_gcode =
between_objects_gcode =
cooling_tube_length = 5
cooling_tube_retraction = 91.5
deretract_speed = 20
end_gcode = M400 ; wait for moves to finish\nM140 S40 ; start bed cooling\nM104 S0 ; disable hotend\nM107 ; disable fans\nG92 E1 ; set extruder to 1mm for retract on print end (LulzBot Cura had 5mm, might be a contributing factor to between print Aerostruder jamming)\nM117 Cooling please wait ; progress indicator message on LCD\nG1 X5 Y5 Z158 E0 F10000 ; move to cooling position\nG1 E1 ; re-prime extruder\nM190 R40 ; wait for bed to cool down to removal temp\nM77 ; Stop GLCD Timer\nG1 X145 F1000 ; move extruder out of the way\nG1 Y175 F1000 ; present finished print\nM140 S0; cool downs\nM84 ; disable steppers\nG90 ; absolute positioning\nM117 Print Complete. ; print complete message\n
extra_loading_move = -2
extruder_colour = ""
extruder_offset = 0x0
gcode_flavor = marlin
high_current_on_filament_swap = 0
host_type = octoprint
inherits =
layer_gcode =
machine_max_acceleration_e = 10000,5000
machine_max_acceleration_extruding = 1500,1250
machine_max_acceleration_retracting = 1500,1250
machine_max_acceleration_x = 9000,1000
machine_max_acceleration_y = 9000,1000
machine_max_acceleration_z = 100,200
machine_max_feedrate_e = 40,120
machine_max_feedrate_x = 800,200
machine_max_feedrate_y = 800,200
machine_max_feedrate_z = 8,12
machine_max_jerk_e = 2.5,2.5
machine_max_jerk_x = 20,10
machine_max_jerk_y = 20,10
machine_max_jerk_z = 0.2,0.4
machine_min_extruding_rate = 0,0
machine_min_travel_rate = 0,0
max_layer_height = 0
max_print_height = 158
min_layer_height = 0.07
nozzle_diameter = 0.5
parking_pos_retraction = 92
print_host =
printer_notes = LulzBot Mini w/ Aerostruder profile for Delaware Library System, Rt9 Library and Innovation Center.
printhost_apikey =
printhost_cafile =
remaining_times = 0
retract_before_travel = 2
retract_before_wipe = 0%
retract_layer_change = 1
retract_length = 1
retract_length_toolchange = 10
retract_lift = 0
retract_lift_above = 0
retract_lift_below = 0
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 40
serial_port =
serial_speed = 250000
silent_mode = 0
single_extruder_multi_material = 0
start_gcode = ;This G-Code has been generated specifically for the LulzBot Mini with Aerosturder\nM73 P0 ; clear GLCD progress bar\nM75 ; start GLCD timer\nG26 ; clear potential 'probe fail' condition\nM107 ; disable fans\nM420 S0 ; disable leveling matrix\nG90 ; absolute positioning\nM82 ; set extruder to absolute mode\nG92 E0 ; set extruder position to 0\nM140 S{first_layer_bed_temperature[0]} ; start bed heating up\nG28; home all axes\nG0 X0 Y187 Z156 F200 ; move away from endstops\nM109 R{first_layer_temperature[0] - 60} ; soften filament before retraction\n;G1 E-15 F75 ; retract filament (LulzBot Cura is apparently trying to cold pull, might be a contributing factor to hob gear filling with filament)\nM109 R{first_layer_temperature[0] - 60} ; wait for extruder to reach wiping temp\nG1 X45 Y173 F11520 ; move above wiper pad\nG1 Z0 F1200 ; push nozzle into wiper\nG1 X42 Y173 Z-.5 F4000 ; wiping\nG1 X52 Y171 Z-.5 F4000 ; wiping\nG1 X42 Y173 Z0 F4000 ; wiping\nG1 X52 Y171 F4000 ; wiping\nG1 X42 Y173 F4000 ; wiping\nG1 X52 Y171 F4000 ; wiping\nG1 X42 Y173 F4000 ; wiping\nG1 X52 Y171 F4000 ; wiping\nG1 X57 Y173 F4000 ; wiping\nG1 X77 Y171 F4000 ; wiping\nG1 X57 Y173 F4000 ; wiping\nG1 X77 Y171 F4000 ; wiping\nG1 X57 Y173 F4000 ; wiping\nG1 X87 Y171 F4000 ; wiping\nG1 X77 Y173 F4000 ; wiping\nG1 X97 Y171 F4000 ; wiping\nG1 X77 Y173 F4000 ; wiping\nG1 X97 Y171 F4000 ; wiping\nG1 X77 Y173 F4000 ; wiping\nG1 X97 Y171 F4000 ; wiping\nG1 X107 Y173 F4000 ; wiping\nG1 X97 Y171 F4000 ; wiping\nG1 X107 Y173 F4000 ; wiping\nG1 X97 Y171 F4000 ; wiping\nG1 X107 Y173 F4000 ; wiping\nG1 X112 Y171 Z-0.5 F1000 ; wiping\nG1 Z10 ; raise extruder\nG28 X0 Y0 ; home X and Y\nG0 X0 Y187 F200 ; move away from endstops\nM109 R{first_layer_temperature[0] - 60} ; wait for extruder to reach probe temp\nM204 S300 ; set probing acceleration\nG29 ; start auto-leveling sequence\nM420 S1 ; enable leveling matrix\nM425 Z ; use measured Z backlash for compensation\nM425 Z F0 ; turn off measured Z backlash compensation. (if activated in the quality settings, this command will automatically be ignored)\nM204 S2000 ; restore standard acceleration\nG28 X0 Y0 ; re-home to account for build variance of earlier mini builds\nG0 X0 Y187 F200 ; move away from endstops\nG0 Y152 F4000 ; move in front of wiper pad\nG4 S1 ; pause\nM400 ; wait for moves to finish\nM117 Heating... ; progress indicator message on LCD\nM109 R{first_layer_temperature[0]} ; wait for extruder to reach printing temp\nM190 R{first_layer_bed_temperature[0]} ; wait for bed to reach printing temp\nG1 Z2 E0 F75 ; prime tiny bit of filament into the nozzle\nM117 Mini Printing... ; progress indicator message on LCD\nM221 S74 ; Printer specific extrusion modifier.
thumbnails =
toolchange_gcode =
use_firmware_retraction = 0
use_relative_e_distances = 0
use_volumetric_e = 0
variable_layer_height = 1
wipe = 1
z_offset = 0
[printer:Taz6 Aero 0.5mm]
printer_model = TAZ6_AERO
printer_variant = 0.5
default_print_profile = 0.3mm @lulzbot
default_filament_profile = PrintedSolid Jesse PLA @lulzbot
bed_shape = 0x0,280x0,280x280,0x280
before_layer_gcode =
between_objects_gcode =
cooling_tube_length = 5
cooling_tube_retraction = 91.5
deretract_speed = 20
end_gcode = M400 ; wait for moves to finish\nM140 S40 ; start bed cooling\nM104 S0 ; disable hotend\nM107 ; disable fans\nG91 ; relative positioning\nG1 E-1 F300 ; filament retraction to release pressure\nG1 Z20 E-5 X-20 Y-20 F3000 ; lift up and retract even more filament\nG1 E6 ; re-prime extruder\nM117 Cooling please wait ; progress indicator message on LCD\nG90 ; absolute positioning\nG1 Y0 F3000 ; move to cooling position\nM190 R40 ; wait for bed to cool down to removal temp\nG1 Y280 F3000 ; present finished print\nM140 S0; cool downs\nM77 ; stop GLCD timer\nM84 ; disable steppers\nG90 ; absolute positioning\nM117 Print Complete. ; print complete message\n
extra_loading_move = -2
extruder_colour = ""
extruder_offset = 0x0
gcode_flavor = marlin
high_current_on_filament_swap = 0
host_type = octoprint
inherits =
layer_gcode =
machine_max_acceleration_e = 1000,5000
machine_max_acceleration_extruding = 1000,1250
machine_max_acceleration_retracting = 1000,1250
machine_max_acceleration_x = 9000,1000
machine_max_acceleration_y = 9000,1000
machine_max_acceleration_z = 100,200
machine_max_feedrate_e = 40,120
machine_max_feedrate_x = 800,200
machine_max_feedrate_y = 800,200
machine_max_feedrate_z = 3,12
machine_max_jerk_e = 2.5,2.5
machine_max_jerk_x = 12,10
machine_max_jerk_y = 12,10
machine_max_jerk_z = 0.2,0.4
machine_min_extruding_rate = 0,0
machine_min_travel_rate = 0,0
max_layer_height = 0
max_print_height = 250
min_layer_height = 0.07
nozzle_diameter = 0.5
parking_pos_retraction = 92
print_host =
printer_notes = LulzBot Taz 6 w/ Aerostruder profile for Delaware Library System, Rt9 Library and Innovation Center.
printer_technology = FFF
printhost_apikey =
printhost_cafile =
remaining_times = 0
retract_before_travel = 2
retract_before_wipe = 0%
retract_layer_change = 0
retract_length = 2
retract_length_toolchange = 10
retract_lift = 0
retract_lift_above = 0
retract_lift_below = 0
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 40
serial_port =
serial_speed = 250000
silent_mode = 0
single_extruder_multi_material = 0
start_gcode = ;This G-Code has been generated specifically for the LulzBot TAZ 6 with Aerosturder\nM73 P0 ; clear GLCD progress bar\nM75 ; start GLCD timer\nG26 ; clear potential 'probe fail' condition\nM107 ; disable fans\nM420 S0 ; disable leveling matrix\nG90 ; absolute positioning\nM82 ; set extruder to absolute mode\nG92 E0 ; set extruder position to 0\nM140 S{first_layer_bed_temperature[0]} ; start bed heating up\nG28 XY ; home X and Y\nG1 X-19 Y258 F1000 ; move to safe homing position\nM109 R{first_layer_temperature[0] - 60} ; soften filament before homing Z\nG28 Z ; home Z\nG1 E-15 F100 ; retract filament\nM109 R{first_layer_temperature[0] - 60} ; wait for extruder to reach wiping temp\nG1 X-15 Y100 F3000 ; move above wiper pad\nG1 Z1 ; push nozzle into wiper\nG1 X-17 Y95 F1000 ; slow wipe\nG1 X-17 Y90 F1000 ; slow wipe\nG1 X-17 Y85 F1000 ; slow wipe\nG1 X-15 Y90 F1000 ; slow wipe\nG1 X-17 Y80 F1000 ; slow wipe\nG1 X-15 Y95 F1000 ; slow wipe\nG1 X-17 Y75 F2000 ; fast wipe\nG1 X-15 Y65 F2000 ; fast wipe\nG1 X-17 Y70 F2000 ; fast wipe\nG1 X-15 Y60 F2000 ; fast wipe\nG1 X-17 Y55 F2000 ; fast wipe\nG1 X-15 Y50 F2000 ; fast wipe\nG1 X-17 Y40 F2000 ; fast wipe\nG1 X-15 Y45 F2000 ; fast wipe\nG1 X-17 Y35 F2000 ; fast wipe\nG1 X-15 Y40 F2000 ; fast wipe\nG1 X-17 Y70 F2000 ; fast wipe\nG1 X-15 Y30 Z2 F2000 ; fast wipe\nG1 X-17 Y35 F2000 ; fast wipe\nG1 X-15 Y25 F2000 ; fast wipe\nG1 X-17 Y30 F2000 ; fast wipe\nG1 X-15 Y25 Z1.5 F1000 ; slow wipe\nG1 X-17 Y23 F1000 ; slow wipe\nG1 Z10 ; raise extruder\nM109 R{first_layer_temperature[0] - 60} ; wait for extruder to reach probe temp\nG1 X-9 Y-9 ; move above first probe point\nM204 S100 ; set probing acceleration\nG29 ; start auto-leveling sequence\nM420 S1 ; enable leveling matrix\nM425 Z ; use measured Z backlash for compensation\nM425 Z F0 ; turn off measured Z backlash compensation. (if activated in the quality settings, this command will automatically be ignored)\nM204 S500 ; restore standard acceleration\nG1 X0 Y0 Z15 F5000 ; move up off last probe point\nG4 S1 ; pause\nM400 ; wait for moves to finish\nM117 Heating... ; progress indicator message on LCD\nM109 R{first_layer_temperature[0]} ; wait for extruder to reach printing temp\nM190 R{first_layer_bed_temperature[0]} ; wait for bed to reach printing temp\nG1 Z2 E0 F75 ; prime tiny bit of filament into the nozzle\nM117 TAZ 6 Printing... ; progress indicator message on LCD\n
thumbnails =
toolchange_gcode =
use_firmware_retraction = 0
use_relative_e_distances = 0
use_volumetric_e = 0
variable_layer_height = 1
wipe = 1
z_offset = 0

View file

@ -104,33 +104,7 @@ endif ()
# Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries. # Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries.
if (SLIC3R_GUI) if (SLIC3R_GUI)
# target_link_libraries(PrusaSlicer ws2_32 uxtheme setupapi libslic3r_gui ${wxWidgets_LIBRARIES}) # target_link_libraries(PrusaSlicer ws2_32 uxtheme setupapi libslic3r_gui ${wxWidgets_LIBRARIES})
target_link_libraries(PrusaSlicer libslic3r_gui ${wxWidgets_LIBRARIES}) target_link_libraries(PrusaSlicer libslic3r_gui)
# Configure libcurl and its dependencies OpenSSL & zlib
find_package(CURL REQUIRED)
if (NOT WIN32)
# Required by libcurl
find_package(ZLIB REQUIRED)
endif()
target_include_directories(PrusaSlicer PRIVATE ${CURL_INCLUDE_DIRS})
target_link_libraries(PrusaSlicer ${CURL_LIBRARIES} ${ZLIB_LIBRARIES})
if (SLIC3R_STATIC)
if (NOT APPLE)
# libcurl is always linked dynamically to the system libcurl on OSX.
# On other systems, libcurl is linked statically if SLIC3R_STATIC is set.
target_compile_definitions(PrusaSlicer PRIVATE CURL_STATICLIB)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
# As of now, our build system produces a statically linked libcurl,
# which links the OpenSSL library dynamically.
find_package(OpenSSL REQUIRED)
message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
message("OpenSSL libraries: ${OPENSSL_LIBRARIES}")
target_include_directories(PrusaSlicer PRIVATE ${OPENSSL_INCLUDE_DIR})
target_link_libraries(PrusaSlicer ${OPENSSL_LIBRARIES})
endif()
endif()
if (MSVC) if (MSVC)
# Generate debug symbols even in release mode. # Generate debug symbols even in release mode.
target_link_options(PrusaSlicer PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>") target_link_options(PrusaSlicer PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")

View file

@ -632,8 +632,11 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
// Negative support_contact_z is not taken into account, it can result in false positives in cases // Negative support_contact_z is not taken into account, it can result in false positives in cases
// where previous layer has object extrusions too (https://github.com/prusa3d/PrusaSlicer/issues/2752) // where previous layer has object extrusions too (https://github.com/prusa3d/PrusaSlicer/issues/2752)
// Only check this layer in case it has some extrusions.
bool has_extrusions = (layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions())
|| (layer_to_print.support_layer && layer_to_print.support_layer->has_extrusions());
if (layer_to_print.print_z() > maximal_print_z + 2. * EPSILON) if (has_extrusions && layer_to_print.print_z() > maximal_print_z + 2. * EPSILON)
throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" + throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" +
_(L("Object name")) + ": " + object.model_object()->name + "\n" + _(L("Print z")) + ": " + _(L("Object name")) + ": " + object.model_object()->name + "\n" + _(L("Print z")) + ": " +
std::to_string(layers_to_print.back().print_z()) + "\n\n" + _(L("This is " std::to_string(layers_to_print.back().print_z()) + "\n\n" + _(L("This is "

View file

@ -212,10 +212,8 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors) if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors)
something_nonoverriddable = false; something_nonoverriddable = false;
for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities
if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region)) { if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region))
something_nonoverriddable = true; something_nonoverriddable = true;
break;
}
} }
if (something_nonoverriddable) if (something_nonoverriddable)
@ -237,7 +235,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
has_infill = true; has_infill = true;
if (m_print_config_ptr) { if (m_print_config_ptr) {
if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable_and_mark(*fill, *m_print_config_ptr, object, region)) if (! layer_tools.wiping_extrusions().is_overriddable_and_mark(*fill, *m_print_config_ptr, object, region))
something_nonoverriddable = true; something_nonoverriddable = true;
} }
} }

View file

@ -12,7 +12,7 @@ PRODUCTVERSION @SLIC3R_RC_VERSION@
VALUE "ProductName", "@SLIC3R_APP_NAME@" VALUE "ProductName", "@SLIC3R_APP_NAME@"
VALUE "ProductVersion", "@SLIC3R_BUILD_ID@" VALUE "ProductVersion", "@SLIC3R_BUILD_ID@"
VALUE "InternalName", "@SLIC3R_APP_NAME@" VALUE "InternalName", "@SLIC3R_APP_NAME@"
VALUE "LegalCopyright", "Copyright \251 2016-2019 Prusa Research, \251 2011-2018 Alessandro Ranelucci" VALUE "LegalCopyright", "Copyright \251 2016-2020 Prusa Research, \251 2011-2018 Alessandro Ranelucci"
VALUE "OriginalFilename", "prusa-slicer.exe" VALUE "OriginalFilename", "prusa-slicer.exe"
} }
} }

View file

@ -5,7 +5,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>@SLIC3R_APP_KEY@</string> <string>@SLIC3R_APP_KEY@</string>
<key>CFBundleGetInfoString</key> <key>CFBundleGetInfoString</key>
<string>@SLIC3R_APP_NAME@ Copyright (C) 2011-2019 Alessandro Ranellucci, (C) 2016-2019 Prusa Reseach</string> <string>@SLIC3R_APP_NAME@ Copyright (C) 2011-2019 Alessandro Ranellucci, (C) 2016-2020 Prusa Reseach</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>PrusaSlicer.icns</string> <string>PrusaSlicer.icns</string>
<key>CFBundleName</key> <key>CFBundleName</key>

View file

@ -191,7 +191,7 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
encoding_check(libslic3r_gui) encoding_check(libslic3r_gui)
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi) target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi libcurl ${wxWidgets_LIBRARIES})
if(APPLE) if(APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY}) target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})

View file

@ -266,7 +266,7 @@ AboutDialog::AboutDialog()
"<html>" "<html>"
"<body bgcolor= %1% link= %2%>" "<body bgcolor= %1% link= %2%>"
"<font color=%3%>" "<font color=%3%>"
"%4% &copy; 2016-2019 Prusa Research. <br />" "%4% &copy; 2016-2020 Prusa Research. <br />"
"%5% &copy; 2011-2018 Alessandro Ranellucci. <br />" "%5% &copy; 2011-2018 Alessandro Ranellucci. <br />"
"<a href=\"http://slic3r.org/\">Slic3r</a> %6% " "<a href=\"http://slic3r.org/\">Slic3r</a> %6% "
"<a href=\"http://www.gnu.org/licenses/agpl-3.0.html\">%7%</a>." "<a href=\"http://www.gnu.org/licenses/agpl-3.0.html\">%7%</a>."

View file

@ -101,10 +101,9 @@ void BackgroundSlicingProcess::process_fff()
//FIXME localize the messages //FIXME localize the messages
// Perform the final post-processing of the export path by applying the print statistics over the file name. // Perform the final post-processing of the export path by applying the print statistics over the file name.
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path); std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
GUI::RemovableDriveManager::get_instance().update(); bool with_check = GUI::wxGetApp().removable_drive_manager()->is_path_on_removable_drive(export_path);
bool with_check = GUI::RemovableDriveManager::get_instance().is_path_on_removable_drive(export_path);
int copy_ret_val = copy_file(m_temp_output_path, export_path, with_check); int copy_ret_val = copy_file(m_temp_output_path, export_path, with_check);
switch (copy_ret_val){ switch (copy_ret_val) {
case SUCCESS: break; // no error case SUCCESS: break; // no error
case FAIL_COPY_FILE: case FAIL_COPY_FILE:
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?"))); throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
@ -236,7 +235,7 @@ void BackgroundSlicingProcess::thread_proc()
// Only post the canceled event, if canceled by user. // Only post the canceled event, if canceled by user.
// Don't post the canceled event, if canceled from Print::apply(). // Don't post the canceled event, if canceled from Print::apply().
wxCommandEvent evt(m_event_finished_id); wxCommandEvent evt(m_event_finished_id);
evt.SetString(error); evt.SetString(GUI::from_u8(error));
evt.SetInt(m_print->canceled() ? -1 : (error.empty() ? 1 : 0)); evt.SetInt(m_print->canceled() ? -1 : (error.empty() ? 1 : 0));
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone()); wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone());
} }

View file

@ -260,7 +260,7 @@ void Camera::debug_render() const
imgui.begin(std::string("Camera statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); imgui.begin(std::string("Camera statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
std::string type = get_type_as_string(); std::string type = get_type_as_string();
if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1")) if (wxGetApp().plater()->get_mouse3d_controller().connected() || (wxGetApp().app_config->get("use_free_camera") == "1"))
type += "/free"; type += "/free";
else else
type += "/constrained"; type += "/constrained";
@ -537,6 +537,7 @@ void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up
Vec3d unit_y = unit_z.cross(unit_x).normalized(); Vec3d unit_y = unit_z.cross(unit_x).normalized();
m_target = target; m_target = target;
m_distance = (position - target).norm();
Vec3d new_position = m_target + m_distance * unit_z; Vec3d new_position = m_target + m_distance * unit_z;
m_view_matrix(0, 0) = unit_x(0); m_view_matrix(0, 0) = unit_x(0);

View file

@ -122,6 +122,8 @@ public:
// returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; } bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }
void look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up);
double max_zoom() const { return 100.0; } double max_zoom() const { return 100.0; }
double min_zoom() const; double min_zoom() const;
@ -137,7 +139,6 @@ private:
#endif // ENABLE_THUMBNAIL_GENERATOR #endif // ENABLE_THUMBNAIL_GENERATOR
void set_distance(double distance) const; void set_distance(double distance) const;
void look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up);
void set_default_orientation(); void set_default_orientation();
Vec3d validate_target(const Vec3d& target) const; Vec3d validate_target(const Vec3d& target) const;
void update_zenit(); void update_zenit();

View file

@ -42,16 +42,27 @@ using Config::SnapshotDB;
// Configuration data structures extensions needed for the wizard // Configuration data structures extensions needed for the wizard
Bundle::Bundle(fs::path source_path, bool is_in_resources, bool is_prusa_bundle) bool Bundle::load(fs::path source_path, bool ais_in_resources, bool ais_prusa_bundle)
: preset_bundle(new PresetBundle)
, vendor_profile(nullptr)
, is_in_resources(is_in_resources)
, is_prusa_bundle(is_prusa_bundle)
{ {
preset_bundle->load_configbundle(source_path.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); this->preset_bundle = std::make_unique<PresetBundle>();
this->is_in_resources = ais_in_resources;
this->is_prusa_bundle = ais_prusa_bundle;
std::string path_string = source_path.string();
size_t presets_loaded = preset_bundle->load_configbundle(path_string, PresetBundle::LOAD_CFGBNDLE_SYSTEM);
auto first_vendor = preset_bundle->vendors.begin(); auto first_vendor = preset_bundle->vendors.begin();
wxCHECK_RET(first_vendor != preset_bundle->vendors.end(), "Failed to load preset bundle"); if (first_vendor == preset_bundle->vendors.end()) {
vendor_profile = &first_vendor->second; BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: No vendor information defined, cannot install.") % path_string;
return false;
}
if (presets_loaded == 0) {
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: No profile loaded.") % path_string;
return false;
}
BOOST_LOG_TRIVIAL(trace) << boost::format("Vendor bundle: `%1%`: %2% profiles loaded.") % path_string % presets_loaded;
this->vendor_profile = &first_vendor->second;
return true;
} }
Bundle::Bundle(Bundle &&other) Bundle::Bundle(Bundle &&other)
@ -76,8 +87,11 @@ BundleMap BundleMap::load()
prusa_bundle_path = (rsrc_vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini"); prusa_bundle_path = (rsrc_vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini");
prusa_bundle_rsrc = true; prusa_bundle_rsrc = true;
} }
Bundle prusa_bundle(std::move(prusa_bundle_path), prusa_bundle_rsrc, true); {
res.emplace(PresetBundle::PRUSA_BUNDLE, std::move(prusa_bundle)); Bundle prusa_bundle;
if (prusa_bundle.load(std::move(prusa_bundle_path), prusa_bundle_rsrc, true))
res.emplace(PresetBundle::PRUSA_BUNDLE, std::move(prusa_bundle));
}
// Load the other bundles in the datadir/vendor directory // Load the other bundles in the datadir/vendor directory
// and then additionally from resources/profiles. // and then additionally from resources/profiles.
@ -90,8 +104,9 @@ BundleMap BundleMap::load()
// Don't load this bundle if we've already loaded it. // Don't load this bundle if we've already loaded it.
if (res.find(id) != res.end()) { continue; } if (res.find(id) != res.end()) { continue; }
Bundle bundle(dir_entry.path(), is_in_resources); Bundle bundle;
res.emplace(std::move(id), std::move(bundle)); if (bundle.load(dir_entry.path(), is_in_resources))
res.emplace(std::move(id), std::move(bundle));
} }
} }

View file

@ -100,13 +100,16 @@ struct Materials
struct Bundle struct Bundle
{ {
std::unique_ptr<PresetBundle> preset_bundle; std::unique_ptr<PresetBundle> preset_bundle;
VendorProfile *vendor_profile; VendorProfile *vendor_profile { nullptr };
const bool is_in_resources; bool is_in_resources { false };
const bool is_prusa_bundle; bool is_prusa_bundle { false };
Bundle(fs::path source_path, bool is_in_resources, bool is_prusa_bundle = false); Bundle() = default;
Bundle(Bundle &&other); Bundle(Bundle &&other);
// Returns false if not loaded. Reason for that is logged as boost::log error.
bool load(fs::path source_path, bool is_in_resources, bool is_prusa_bundle = false);
const std::string& vendor_id() const { return vendor_profile->id; } const std::string& vendor_id() const { return vendor_profile->id; }
}; };

View file

@ -40,11 +40,19 @@ template<class T, size_t N> struct ArrayEvent : public wxEvent
return new ArrayEvent<T, N>(GetEventType(), data, GetEventObject()); return new ArrayEvent<T, N>(GetEventType(), data, GetEventObject());
} }
}; };
template<class T> struct ArrayEvent<T, 1> : public wxEvent
template<class T> struct Event : public wxEvent
{ {
T data; T data;
ArrayEvent(wxEventType type, T data, wxObject* origin = nullptr) Event(wxEventType type, const T &data, wxObject* origin = nullptr)
: wxEvent(0, type), data(std::move(data))
{
m_propagationLevel = wxEVENT_PROPAGATE_MAX;
SetEventObject(origin);
}
Event(wxEventType type, T&& data, wxObject* origin = nullptr)
: wxEvent(0, type), data(std::move(data)) : wxEvent(0, type), data(std::move(data))
{ {
m_propagationLevel = wxEVENT_PROPAGATE_MAX; m_propagationLevel = wxEVENT_PROPAGATE_MAX;
@ -53,13 +61,10 @@ template<class T> struct ArrayEvent<T, 1> : public wxEvent
virtual wxEvent* Clone() const virtual wxEvent* Clone() const
{ {
return new ArrayEvent<T, 1>(GetEventType(), data, GetEventObject()); return new Event<T>(GetEventType(), data, GetEventObject());
} }
}; };
template <class T> using Event = ArrayEvent<T, 1>;
} }
} }

View file

@ -4088,12 +4088,6 @@ void GLCanvas3D::handle_layers_data_focus_event(const t_layer_height_range range
void GLCanvas3D::update_ui_from_settings() void GLCanvas3D::update_ui_from_settings()
{ {
#if ENABLE_NON_STATIC_CANVAS_MANAGER
Camera& camera = wxGetApp().plater()->get_camera();
camera.set_type(wxGetApp().app_config->get("use_perspective_camera"));
#else
m_camera.set_type(wxGetApp().app_config->get("use_perspective_camera"));
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
m_dirty = true; m_dirty = true;
#if ENABLE_RETINA_GL #if ENABLE_RETINA_GL

View file

@ -155,6 +155,7 @@ GUI_App::GUI_App()
, m_em_unit(10) , m_em_unit(10)
, m_imgui(new ImGuiWrapper()) , m_imgui(new ImGuiWrapper())
, m_wizard(nullptr) , m_wizard(nullptr)
, m_removable_drive_manager(std::make_unique<RemovableDriveManager>())
{} {}
GUI_App::~GUI_App() GUI_App::~GUI_App()
@ -279,7 +280,6 @@ bool GUI_App::on_init_inner()
m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg())); m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg()));
RemovableDriveManager::get_instance().init();
Bind(wxEVT_IDLE, [this](wxIdleEvent& event) Bind(wxEVT_IDLE, [this](wxIdleEvent& event)
{ {
@ -291,10 +291,6 @@ bool GUI_App::on_init_inner()
this->obj_manipul()->update_if_dirty(); this->obj_manipul()->update_if_dirty();
#if !__APPLE__
RemovableDriveManager::get_instance().update(wxGetLocalTime(), true);
#endif
// Preset updating & Configwizard are done after the above initializations, // Preset updating & Configwizard are done after the above initializations,
// and after MainFrame is created & shown. // and after MainFrame is created & shown.
// The extra CallAfter() is needed because of Mac, where this is the only way // The extra CallAfter() is needed because of Mac, where this is the only way
@ -454,46 +450,30 @@ float GUI_App::toolbar_icon_scale(const bool is_limited/* = false*/) const
void GUI_App::recreate_GUI() void GUI_App::recreate_GUI()
{ {
// Weird things happen as the Paint messages are floating around the windows being destructed. mainframe->shutdown();
// Avoid the Paint messages by hiding the main window.
// Also the application closes much faster without these unnecessary screen refreshes.
// In addition, there were some crashes due to the Paint events sent to already destructed windows.
mainframe->Show(false);
const auto msg_name = _(L("Changing of an application language")) + dots; const auto msg_name = _(L("Changing of an application language")) + dots;
wxProgressDialog dlg(msg_name, msg_name); wxProgressDialog dlg(msg_name, msg_name);
dlg.Pulse(); dlg.Pulse();
// to make sure nobody accesses data from the soon-to-be-destroyed widgets:
tabs_list.clear();
plater_ = nullptr;
dlg.Update(10, _(L("Recreating")) + dots); dlg.Update(10, _(L("Recreating")) + dots);
MainFrame* topwindow = mainframe; MainFrame *old_main_frame = mainframe;
mainframe = new MainFrame(); mainframe = new MainFrame();
sidebar().obj_list()->init_objects(); // propagate model objects to object list // Propagate model objects to object list.
sidebar().obj_list()->init_objects();
SetTopWindow(mainframe);
if (topwindow) { dlg.Update(30, _(L("Recreating")) + dots);
SetTopWindow(mainframe); old_main_frame->Destroy();
// For this moment ConfigWizard is deleted, invalidate it.
dlg.Update(30, _(L("Recreating")) + dots); m_wizard = nullptr;
topwindow->Destroy();
// For this moment ConfigWizard is deleted, invalidate it
m_wizard = nullptr;
}
dlg.Update(80, _(L("Loading of current presets")) + dots); dlg.Update(80, _(L("Loading of current presets")) + dots);
m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg())); m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg()));
load_current_presets(); load_current_presets();
mainframe->Show(true); mainframe->Show(true);
dlg.Update(90, _(L("Loading of a mode view")) + dots); dlg.Update(90, _(L("Loading of a mode view")) + dots);
/* Temporary workaround for the correct behavior of the Scrolled sidebar panel: /* Temporary workaround for the correct behavior of the Scrolled sidebar panel:
* change min hight of object list to the normal min value (15 * wxGetApp().em_unit()) * change min hight of object list to the normal min value (15 * wxGetApp().em_unit())
* after first whole Mainframe updating/layouting * after first whole Mainframe updating/layouting
@ -501,7 +481,6 @@ void GUI_App::recreate_GUI()
const int list_min_height = 15 * em_unit(); const int list_min_height = 15 * em_unit();
if (obj_list()->GetMinSize().GetY() > list_min_height) if (obj_list()->GetMinSize().GetY() > list_min_height)
obj_list()->SetMinSize(wxSize(-1, list_min_height)); obj_list()->SetMinSize(wxSize(-1, list_min_height));
update_mode(); update_mode();
// #ys_FIXME_delete_after_testing Do we still need this ? // #ys_FIXME_delete_after_testing Do we still need this ?
@ -596,9 +575,6 @@ void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const
bool GUI_App::switch_language() bool GUI_App::switch_language()
{ {
if (select_language()) { if (select_language()) {
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
_3DScene::remove_all_canvases();
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
recreate_GUI(); recreate_GUI();
return true; return true;
} else { } else {

View file

@ -32,9 +32,9 @@ class PresetUpdater;
class ModelObject; class ModelObject;
class PrintHostJobQueue; class PrintHostJobQueue;
namespace GUI
{
namespace GUI{
class RemovableDriveManager;
enum FileType enum FileType
{ {
FT_STL, FT_STL,
@ -102,6 +102,9 @@ class GUI_App : public wxApp
#if ENABLE_NON_STATIC_CANVAS_MANAGER #if ENABLE_NON_STATIC_CANVAS_MANAGER
GLCanvas3DManager m_canvas_mgr; GLCanvas3DManager m_canvas_mgr;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
std::unique_ptr<RemovableDriveManager> m_removable_drive_manager;
std::unique_ptr<ImGuiWrapper> m_imgui; std::unique_ptr<ImGuiWrapper> m_imgui;
std::unique_ptr<PrintHostJobQueue> m_printhost_job_queue; std::unique_ptr<PrintHostJobQueue> m_printhost_job_queue;
ConfigWizard* m_wizard; // Managed by wxWindow tree ConfigWizard* m_wizard; // Managed by wxWindow tree
@ -192,6 +195,8 @@ public:
std::vector<Tab *> tabs_list; std::vector<Tab *> tabs_list;
RemovableDriveManager* removable_drive_manager() { return m_removable_drive_manager.get(); }
ImGuiWrapper* imgui() { return m_imgui.get(); } ImGuiWrapper* imgui() { return m_imgui.get(); }
PrintHostJobQueue& printhost_job_queue() { return *m_printhost_job_queue.get(); } PrintHostJobQueue& printhost_job_queue() { return *m_printhost_job_queue.get(); }

View file

@ -122,6 +122,8 @@ void KBShortcutsDialog::fill_shortcuts()
{ ctrl + "G", L("Export G-code") }, { ctrl + "G", L("Export G-code") },
{ ctrl + "Shift+" + "G", L("Send G-code") }, { ctrl + "Shift+" + "G", L("Send G-code") },
{ ctrl + "E", L("Export config") }, { ctrl + "E", L("Export config") },
{ ctrl + "U", L("Export to SD card / Flash drive") },
{ ctrl + "T", L("Eject SD card / Flash drive") },
// Edit // Edit
{ ctrl + "A", L("Select all objects") }, { ctrl + "A", L("Select all objects") },
{ "Esc", L("Deselect all") }, { "Esc", L("Deselect all") },

View file

@ -25,6 +25,7 @@
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#include "Mouse3DController.hpp" #include "Mouse3DController.hpp"
#include "RemovableDriveManager.hpp"
#include "I18N.hpp" #include "I18N.hpp"
#include <fstream> #include <fstream>
@ -108,44 +109,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
event.Veto(); event.Veto();
return; return;
} }
this->shutdown();
if (m_plater)
m_plater->stop_jobs();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
// Unbinding of wxWidgets event handling in canvases needs to be done here because on MAC,
// when closing the application using Command+Q, a mouse event is triggered after this lambda is completed,
// causing a crash
if (m_plater) m_plater->unbind_canvas_event_handlers();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
// Weird things happen as the Paint messages are floating around the windows being destructed.
// Avoid the Paint messages by hiding the main window.
// Also the application closes much faster without these unnecessary screen refreshes.
// In addition, there were some crashes due to the Paint events sent to already destructed windows.
this->Show(false);
// Stop the background thread (Windows and Linux).
// Disconnect from a 3DConnextion driver (OSX).
m_plater->get_mouse3d_controller().shutdown();
// Store the device parameter database back to appconfig.
m_plater->get_mouse3d_controller().save_config(*wxGetApp().app_config);
// Save the slic3r.ini.Usually the ini file is saved from "on idle" callback,
// but in rare cases it may not have been called yet.
wxGetApp().app_config->save();
// if (m_plater)
// m_plater->print = undef;
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
_3DScene::remove_all_canvases();
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
// Slic3r::GUI::deregister_on_request_update_callback();
// set to null tabs and a plater
// to avoid any manipulations with them from App->wxEVT_IDLE after of the mainframe closing
wxGetApp().tabs_list.clear();
wxGetApp().plater_ = nullptr;
// propagate event // propagate event
event.Skip(); event.Skip();
}); });
@ -164,6 +128,50 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
m_plater->show_action_buttons(true); m_plater->show_action_buttons(true);
} }
// Called when closing the application and when switching the application language.
void MainFrame::shutdown()
{
if (m_plater)
m_plater->stop_jobs();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
// Unbinding of wxWidgets event handling in canvases needs to be done here because on MAC,
// when closing the application using Command+Q, a mouse event is triggered after this lambda is completed,
// causing a crash
if (m_plater) m_plater->unbind_canvas_event_handlers();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
// Weird things happen as the Paint messages are floating around the windows being destructed.
// Avoid the Paint messages by hiding the main window.
// Also the application closes much faster without these unnecessary screen refreshes.
// In addition, there were some crashes due to the Paint events sent to already destructed windows.
this->Show(false);
// Stop the background thread (Windows and Linux).
// Disconnect from a 3DConnextion driver (OSX).
m_plater->get_mouse3d_controller().shutdown();
// Store the device parameter database back to appconfig.
m_plater->get_mouse3d_controller().save_config(*wxGetApp().app_config);
// Stop the background thread of the removable drive manager, so that no new updates will be sent to the Plater.
wxGetApp().removable_drive_manager()->shutdown();
// Save the slic3r.ini.Usually the ini file is saved from "on idle" callback,
// but in rare cases it may not have been called yet.
wxGetApp().app_config->save();
// if (m_plater)
// m_plater->print = undef;
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
_3DScene::remove_all_canvases();
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
// Slic3r::GUI::deregister_on_request_update_callback();
// set to null tabs and a plater
// to avoid any manipulations with them from App->wxEVT_IDLE after of the mainframe closing
wxGetApp().tabs_list.clear();
wxGetApp().plater_ = nullptr;
}
void MainFrame::update_title() void MainFrame::update_title()
{ {
wxString title = wxEmptyString; wxString title = wxEmptyString;
@ -332,6 +340,27 @@ bool MainFrame::can_send_gcode() const
return print_host_opt != nullptr && !print_host_opt->value.empty(); return print_host_opt != nullptr && !print_host_opt->value.empty();
} }
bool MainFrame::can_export_gcode_sd() const
{
if (m_plater == nullptr)
return false;
if (m_plater->model().objects.empty())
return false;
if (m_plater->is_export_gcode_scheduled())
return false;
// TODO:: add other filters
return wxGetApp().removable_drive_manager()->status().has_removable_drives;
}
bool MainFrame::can_eject() const
{
return wxGetApp().removable_drive_manager()->status().has_eject;
}
bool MainFrame::can_slice() const bool MainFrame::can_slice() const
{ {
bool bg_proc = wxGetApp().app_config->get("background_processing") == "1"; bool bg_proc = wxGetApp().app_config->get("background_processing") == "1";
@ -438,7 +467,7 @@ void MainFrame::init_menubar()
m_plater->load_project(filename); m_plater->load_project(filename);
else else
{ {
wxMessageDialog msg(this, _(L("The selected project is no longer available.\nDo you want to remove it from the recent projects list ?")), _(L("Error")), wxYES_NO | wxYES_DEFAULT); wxMessageDialog msg(this, _(L("The selected project is no longer available.\nDo you want to remove it from the recent projects list?")), _(L("Error")), wxYES_NO | wxYES_DEFAULT);
if (msg.ShowModal() == wxID_YES) if (msg.ShowModal() == wxID_YES)
{ {
m_recent_projects.RemoveFileFromHistory(file_id); m_recent_projects.RemoveFileFromHistory(file_id);
@ -502,6 +531,9 @@ void MainFrame::init_menubar()
[this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, "export_gcode", nullptr, [this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, "export_gcode", nullptr,
[this](){return can_send_gcode(); }, this); [this](){return can_send_gcode(); }, this);
m_changeable_menu_items.push_back(item_send_gcode); m_changeable_menu_items.push_back(item_send_gcode);
append_menu_item(export_menu, wxID_ANY, _(L("Export G-code to SD card / Flash drive")) + dots + "\tCtrl+U", _(L("Export current plate as G-code to SD card / Flash drive")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(true); }, "export_to_sd", nullptr,
[this]() {return can_export_gcode_sd(); }, this);
export_menu->AppendSeparator(); export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")), append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "export_plater", nullptr, [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "export_plater", nullptr,
@ -525,6 +557,10 @@ void MainFrame::init_menubar()
[this]() {return true; }, this); [this]() {return true; }, this);
append_submenu(fileMenu, export_menu, wxID_ANY, _(L("&Export")), ""); append_submenu(fileMenu, export_menu, wxID_ANY, _(L("&Export")), "");
append_menu_item(fileMenu, wxID_ANY, _(L("Ejec&t SD card / Flash drive")) + dots + "\tCtrl+T", _(L("Eject SD card / Flash drive after the G-code was exported to it.")),
[this](wxCommandEvent&) { if (m_plater) m_plater->eject_drive(); }, "eject_sd", nullptr,
[this]() {return can_eject(); }, this);
fileMenu->AppendSeparator(); fileMenu->AppendSeparator();
#if 0 #if 0

View file

@ -70,6 +70,8 @@ class MainFrame : public DPIFrame
bool can_export_supports() const; bool can_export_supports() const;
bool can_export_gcode() const; bool can_export_gcode() const;
bool can_send_gcode() const; bool can_send_gcode() const;
bool can_export_gcode_sd() const;
bool can_eject() const;
bool can_slice() const; bool can_slice() const;
bool can_change_view() const; bool can_change_view() const;
bool can_select() const; bool can_select() const;
@ -98,6 +100,9 @@ public:
MainFrame(); MainFrame();
~MainFrame() = default; ~MainFrame() = default;
// Called when closing the application and when switching the application language.
void shutdown();
Plater* plater() { return m_plater; } Plater* plater() { return m_plater; }
void update_title(); void update_title();

View file

@ -368,6 +368,8 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
void Mouse3DController::connected(std::string device_name) void Mouse3DController::connected(std::string device_name)
{ {
assert(! m_connected);
assert(m_device_str.empty());
m_device_str = device_name; m_device_str = device_name;
// Copy the parameters for m_device_str into the current parameters. // Copy the parameters for m_device_str into the current parameters.
if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end()) { if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end()) {
@ -380,13 +382,13 @@ void Mouse3DController::connected(std::string device_name)
void Mouse3DController::disconnected() void Mouse3DController::disconnected()
{ {
// Copy the current parameters for m_device_str into the parameter database. // Copy the current parameters for m_device_str into the parameter database.
assert(! m_device_str.empty()); assert(m_connected == ! m_device_str.empty());
if (! m_device_str.empty()) { if (m_connected) {
tbb::mutex::scoped_lock lock(m_params_ui_mutex); tbb::mutex::scoped_lock lock(m_params_ui_mutex);
m_params_by_device[m_device_str] = m_params_ui; m_params_by_device[m_device_str] = m_params_ui;
m_device_str.clear();
m_connected = false;
} }
m_device_str.clear();
m_connected = false;
} }
bool Mouse3DController::handle_input(const DataPacketAxis& packet) bool Mouse3DController::handle_input(const DataPacketAxis& packet)
@ -451,12 +453,13 @@ void Mouse3DController::shutdown()
// Stop the worker thread, if running. // Stop the worker thread, if running.
{ {
// Notify the worker thread to cancel wait on detection polling. // Notify the worker thread to cancel wait on detection polling.
std::unique_lock<std::mutex> lock(m_stop_condition_mutex); std::lock_guard<std::mutex> lock(m_stop_condition_mutex);
m_stop = true; m_stop = true;
m_stop_condition.notify_all();
} }
m_stop_condition.notify_all();
// Wait for the worker thread to stop. // Wait for the worker thread to stop.
m_thread.join(); m_thread.join();
m_stop = false;
} }
} }

View file

@ -12,6 +12,7 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <chrono> #include <chrono>
#include <condition_variable>
#include <tbb/mutex.h> #include <tbb/mutex.h>
@ -138,7 +139,7 @@ class Mouse3DController
std::map<std::string, Params> m_params_by_device; std::map<std::string, Params> m_params_by_device;
mutable State m_state; mutable State m_state;
std::atomic<bool> m_connected; std::atomic<bool> m_connected { false };
std::string m_device_str; std::string m_device_str;
#if ! __APPLE__ #if ! __APPLE__

View file

@ -152,6 +152,8 @@ static void DeviceAdded(uint32_t unused)
static void DeviceRemoved(uint32_t unused) static void DeviceRemoved(uint32_t unused)
{ {
BOOST_LOG_TRIVIAL(info) << "3dx device removed\n"; BOOST_LOG_TRIVIAL(info) << "3dx device removed\n";
assert(m_connected);
assert(! m_device_str.empty());
mouse_3d_controller->disconnected(); mouse_3d_controller->disconnected();
} }
@ -214,6 +216,8 @@ void Mouse3DController::shutdown()
CleanupConnexionHandlers(); CleanupConnexionHandlers();
unload_driver(); unload_driver();
} }
// Copy the current parameters to parameter database, mark the device as disconnected.
this->disconnected();
mouse_3d_controller = nullptr; mouse_3d_controller = nullptr;
} }

View file

@ -81,7 +81,7 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), -1)); html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), -1));
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK); // wxSYS_COLOUR_WINDOW 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 text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); auto 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; const int font_size = font.GetPointSize()-1;

View file

@ -113,7 +113,11 @@ void OptionsGroup::add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& fiel
} }
void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = nullptr*/) { void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = nullptr*/) {
if ( (line.sizer != nullptr || line.widget != nullptr) && line.full_width) { if ( line.full_width && (
line.sizer != nullptr ||
line.widget != nullptr ||
!line.get_extra_widgets().empty() )
) {
if (line.sizer != nullptr) { if (line.sizer != nullptr) {
sizer->Add(line.sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 15); sizer->Add(line.sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 15);
return; return;
@ -122,6 +126,17 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
sizer->Add(line.widget(this->ctrl_parent()), 0, wxEXPAND | wxALL, wxOSX ? 0 : 15); sizer->Add(line.widget(this->ctrl_parent()), 0, wxEXPAND | wxALL, wxOSX ? 0 : 15);
return; return;
} }
if (!line.get_extra_widgets().empty()) {
const auto h_sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(h_sizer, 1, wxEXPAND | wxALL, wxOSX ? 0 : 15);
bool is_first_item = true;
for (auto extra_widget : line.get_extra_widgets()) {
h_sizer->Add(extra_widget(this->ctrl_parent()), is_first_item ? 1 : 0, wxLEFT, 15);
is_first_item = false;
}
return;
}
} }
auto option_set = line.get_options(); auto option_set = line.get_options();
@ -412,7 +427,9 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config,
auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(config.option("nozzle_diameter")); auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(config.option("nozzle_diameter"));
value = int(nozzle_diameter->values.size()); value = int(nozzle_diameter->values.size());
} }
else if (m_opt_map.find(opt_key) == m_opt_map.end() || opt_key == "bed_shape") { else if (m_opt_map.find(opt_key) == m_opt_map.end() ||
// This option don't have corresponded field
opt_key == "bed_shape" || opt_key == "compatible_printers" || opt_key == "compatible_prints" ) {
value = get_config_value(config, opt_key); value = get_config_value(config, opt_key);
change_opt_value(*m_config, opt_key, value); change_opt_value(*m_config, opt_key, value);
return; return;
@ -629,7 +646,7 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
ret = static_cast<wxString>(config.opt_string(opt_key)); ret = static_cast<wxString>(config.opt_string(opt_key));
break; break;
case coStrings: case coStrings:
if (opt_key.compare("compatible_printers") == 0) { if (opt_key == "compatible_printers" || opt_key == "compatible_prints") {
ret = config.option<ConfigOptionStrings>(opt_key)->values; ret = config.option<ConfigOptionStrings>(opt_key)->values;
break; break;
} }

View file

@ -301,15 +301,20 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
if (preset_type == Slic3r::Preset::TYPE_FILAMENT) if (preset_type == Slic3r::Preset::TYPE_FILAMENT)
{ {
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) { Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
int shifl_Left = 0; PresetBundle* preset_bundle = wxGetApp().preset_bundle;
const Preset* selected_preset = preset_bundle->filaments.find_preset(preset_bundle->filament_presets[extruder_idx]);
// Wide icons are shown if the currently selected preset is not compatible with the current printer,
// and red flag is drown in front of the selected preset.
bool wide_icons = selected_preset != nullptr && !selected_preset->is_compatible;
float scale = m_em_unit*0.1f; float scale = m_em_unit*0.1f;
int shifl_Left = wide_icons ? int(scale * 16 + 0.5) : 0;
#if defined(wxBITMAPCOMBOBOX_OWNERDRAWN_BASED) #if defined(wxBITMAPCOMBOBOX_OWNERDRAWN_BASED)
shifl_Left = int(scale * 4 + 0.5f); // IMAGE_SPACING_RIGHT = 4 for wxBitmapComboBox -> Space left of image shifl_Left += int(scale * 4 + 0.5f); // IMAGE_SPACING_RIGHT = 4 for wxBitmapComboBox -> Space left of image
#endif #endif
int icon_right_pos = int(scale * (24+4) + 0.5); int icon_right_pos = shifl_Left + int(scale * (24+4) + 0.5);
int mouse_pos = event.GetLogicalPosition(wxClientDC(this)).x; int mouse_pos = event.GetLogicalPosition(wxClientDC(this)).x;
// if (extruder_idx < 0 || event.GetLogicalPosition(wxClientDC(this)).x > 24) { if (mouse_pos < shifl_Left || mouse_pos > icon_right_pos ) {
if ( extruder_idx < 0 || mouse_pos < shifl_Left || mouse_pos > icon_right_pos ) {
// Let the combo box process the mouse click. // Let the combo box process the mouse click.
event.Skip(); event.Skip();
return; return;
@ -338,7 +343,7 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
cfg_new.set_key_value("extruder_colour", colors); cfg_new.set_key_value("extruder_colour", colors);
wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg_new); wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg_new);
wxGetApp().preset_bundle->update_plater_filament_ui(extruder_idx, this); preset_bundle->update_plater_filament_ui(extruder_idx, this);
wxGetApp().plater()->on_config_change(cfg_new); wxGetApp().plater()->on_config_change(cfg_new);
} }
}); });
@ -881,8 +886,8 @@ Sidebar::Sidebar(Plater *parent)
}; };
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")) + "\tCtrl+Shift+G"); init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")) + "\tCtrl+Shift+G");
init_scalable_btn(&p->btn_remove_device, "eject_sd" , _(L("Remove device"))); init_scalable_btn(&p->btn_remove_device, "eject_sd" , _(L("Remove device")) + "\tCtrl+T");
init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _(L("Export to SD card / Flash drive"))); init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _(L("Export to SD card / Flash drive")) + "\tCtrl+U");
// regular buttons "Slice now" and "Export G-code" // regular buttons "Slice now" and "Export G-code"
@ -1509,6 +1514,7 @@ struct Plater::priv
ret.poly.contour = std::move(p); ret.poly.contour = std::move(p);
ret.translation = scaled(m_pos); ret.translation = scaled(m_pos);
ret.rotation = m_rotation; ret.rotation = m_rotation;
ret.priority++;
return ret; return ret;
} }
} wipetower; } wipetower;
@ -1572,18 +1578,23 @@ struct Plater::priv
// the current bed width. // the current bed width.
static const constexpr double LOGICAL_BED_GAP = 1. / 5.; static const constexpr double LOGICAL_BED_GAP = 1. / 5.;
ArrangePolygons m_selected, m_unselected; ArrangePolygons m_selected, m_unselected, m_unprintable;
// clear m_selected and m_unselected, reserve space for next usage // clear m_selected and m_unselected, reserve space for next usage
void clear_input() { void clear_input() {
const Model &model = plater().model; const Model &model = plater().model;
size_t count = 0; // To know how much space to reserve size_t count = 0, cunprint = 0; // To know how much space to reserve
for (auto obj : model.objects) count += obj->instances.size(); for (auto obj : model.objects)
for (auto mi : obj->instances)
mi->printable ? count++ : cunprint++;
m_selected.clear(); m_selected.clear();
m_unselected.clear(); m_unselected.clear();
m_unprintable.clear();
m_selected.reserve(count + 1 /* for optional wti */); m_selected.reserve(count + 1 /* for optional wti */);
m_unselected.reserve(count + 1 /* for optional wti */); m_unselected.reserve(count + 1 /* for optional wti */);
m_unprintable.reserve(cunprint /* for optional wti */);
} }
// Stride between logical beds // Stride between logical beds
@ -1612,8 +1623,10 @@ struct Plater::priv
clear_input(); clear_input();
for (ModelObject *obj: plater().model.objects) for (ModelObject *obj: plater().model.objects)
for (ModelInstance *mi : obj->instances) for (ModelInstance *mi : obj->instances) {
m_selected.emplace_back(get_arrange_poly(mi)); ArrangePolygons & cont = mi->printable ? m_selected : m_unprintable;
cont.emplace_back(get_arrange_poly(mi));
}
auto& wti = plater().updated_wipe_tower(); auto& wti = plater().updated_wipe_tower();
if (wti) m_selected.emplace_back(get_arrange_poly(&wti)); if (wti) m_selected.emplace_back(get_arrange_poly(&wti));
@ -1648,9 +1661,12 @@ struct Plater::priv
for (size_t i = 0; i < inst_sel.size(); ++i) { for (size_t i = 0; i < inst_sel.size(); ++i) {
ArrangePolygon &&ap = get_arrange_poly(mo->instances[i]); ArrangePolygon &&ap = get_arrange_poly(mo->instances[i]);
inst_sel[i] ? ArrangePolygons &cont = mo->instances[i]->printable ?
m_selected.emplace_back(std::move(ap)) : (inst_sel[i] ? m_selected :
m_unselected.emplace_back(std::move(ap)); m_unselected) :
m_unprintable;
cont.emplace_back(std::move(ap));
} }
} }
@ -1682,7 +1698,10 @@ struct Plater::priv
public: public:
using PlaterJob::PlaterJob; using PlaterJob::PlaterJob;
int status_range() const override { return int(m_selected.size()); } int status_range() const override
{
return int(m_selected.size() + m_unprintable.size());
}
void process() override; void process() override;
@ -1690,8 +1709,24 @@ struct Plater::priv
// Ignore the arrange result if aborted. // Ignore the arrange result if aborted.
if (was_canceled()) return; if (was_canceled()) return;
// Unprintable items go to the last virtual bed
int beds = 0;
// Apply the arrange result to all selected objects // Apply the arrange result to all selected objects
for (ArrangePolygon &ap : m_selected) ap.apply(); for (ArrangePolygon &ap : m_selected) {
beds = std::max(ap.bed_idx, beds);
ap.apply();
}
// Get the virtual beds from the unselected items
for (ArrangePolygon &ap : m_unselected)
beds = std::max(ap.bed_idx, beds);
// Move the unprintable items to the last virtual bed.
for (ArrangePolygon &ap : m_unprintable) {
ap.bed_idx += beds + 1;
ap.apply();
}
plater().update(); plater().update();
} }
@ -1961,6 +1996,11 @@ struct Plater::priv
wxString get_project_filename(const wxString& extension = wxEmptyString) const; wxString get_project_filename(const wxString& extension = wxEmptyString) const;
void set_project_filename(const wxString& filename); void set_project_filename(const wxString& filename);
// Caching last value of show_action_buttons parameter for show_action_buttons(), so that a callback which does not know this state will not override it.
mutable bool ready_to_slice = { false };
// Flag indicating that the G-code export targets a removable device, therefore the show_action_buttons() needs to be called at any case when the background processing finishes.
bool writing_to_removable_device = { false };
private: private:
bool init_object_menu(); bool init_object_menu();
bool init_common_menu(wxMenu* menu, const bool is_part = false); bool init_common_menu(wxMenu* menu, const bool is_part = false);
@ -1986,8 +2026,8 @@ private:
* we should call tack_snapshot just ones * we should call tack_snapshot just ones
* instead of calls for each action separately * instead of calls for each action separately
* */ * */
std::string m_last_fff_printer_profile_name; std::string m_last_fff_printer_profile_name;
std::string m_last_sla_printer_profile_name; std::string m_last_sla_printer_profile_name;
}; };
const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase); const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase);
@ -2171,11 +2211,17 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// Connect to a 3DConnextion driver (OSX). // Connect to a 3DConnextion driver (OSX).
mouse3d_controller.init(); mouse3d_controller.init();
this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this](RemovableDriveEjectEvent &evt) {
this->show_action_buttons(this->ready_to_slice);
Slic3r::GUI::show_info(this->q, (boost::format(_utf8(L("Unmounting successful. The device %s(%s) can now be safely removed from the computer.")))
% evt.data.name % evt.data.path).str());
});
this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this](RemovableDrivesChangedEvent &) { this->show_action_buttons(this->ready_to_slice); });
// Start the background thread and register this window as a target for update events.
wxGetApp().removable_drive_manager()->init(this->q);
// Initialize the Undo / Redo stack with a first snapshot. // Initialize the Undo / Redo stack with a first snapshot.
this->take_snapshot(_(L("New Project"))); this->take_snapshot(_(L("New Project")));
//void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
RemovableDriveManager::get_instance().set_drive_count_changed_callback(std::bind(&Plater::priv::show_action_buttons, this, std::placeholders::_1));
} }
Plater::priv::~priv() Plater::priv::~priv()
@ -2249,6 +2295,14 @@ void Plater::priv::update_ui_from_settings()
// $self->{buttons_sizer}->Layout; // $self->{buttons_sizer}->Layout;
// } // }
camera.set_type(wxGetApp().app_config->get("use_perspective_camera"));
if (wxGetApp().app_config->get("use_free_camera") != "1")
{
// forces camera right vector to be parallel to XY plane
if (std::abs(camera.get_dir_right()(2)) > EPSILON)
camera.look_at(camera.get_position(), camera.get_target(), Vec3d::UnitZ());
}
view3D->get_canvas3d()->update_ui_from_settings(); view3D->get_canvas3d()->update_ui_from_settings();
preview->get_canvas3d()->update_ui_from_settings(); preview->get_canvas3d()->update_ui_from_settings();
} }
@ -2842,16 +2896,21 @@ void Plater::priv::ArrangeJob::process() {
} }
coord_t min_d = scaled(dist); coord_t min_d = scaled(dist);
auto count = unsigned(m_selected.size()); auto count = unsigned(m_selected.size() + m_unprintable.size());
arrangement::BedShapeHint bedshape = plater().get_bed_shape_hint(); arrangement::BedShapeHint bedshape = plater().get_bed_shape_hint();
auto stopfn = [this]() { return was_canceled(); };
try { try {
arrangement::arrange(m_selected, m_unselected, min_d, bedshape, arrangement::arrange(m_selected, m_unselected, min_d, bedshape,
[this, count](unsigned st) { [this, count](unsigned st) {
if (st > 0) // will not finalize after last one st += m_unprintable.size();
update_status(int(count - st), arrangestr); if (st > 0) update_status(int(count - st), arrangestr);
}, }, stopfn);
[this]() { return was_canceled(); }); arrangement::arrange(m_unprintable, {}, min_d, bedshape,
[this, count](unsigned st) {
if (st > 0) update_status(int(count - st), arrangestr);
}, stopfn);
} catch (std::exception & /*e*/) { } catch (std::exception & /*e*/) {
GUI::show_error(plater().q, GUI::show_error(plater().q,
_(L("Could not arrange model objects! " _(L("Could not arrange model objects! "
@ -3717,14 +3776,9 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
sidebar->set_btn_label(ActionButtonType::abReslice, "Slice now"); sidebar->set_btn_label(ActionButtonType::abReslice, "Slice now");
show_action_buttons(true); show_action_buttons(true);
} }
else if (wxGetApp().get_mode() == comSimple) else if (this->writing_to_removable_device || wxGetApp().get_mode() == comSimple)
show_action_buttons(false);
if(!canceled && RemovableDriveManager::get_instance().get_is_writing())
{
RemovableDriveManager::get_instance().set_is_writing(false);
show_action_buttons(false); show_action_buttons(false);
} this->writing_to_removable_device = false;
} }
void Plater::priv::on_layer_editing_toggled(bool enable) void Plater::priv::on_layer_editing_toggled(bool enable)
@ -4295,32 +4349,36 @@ void Plater::priv::update_object_menu()
sidebar->obj_list()->append_menu_items_add_volume(&object_menu); sidebar->obj_list()->append_menu_items_add_volume(&object_menu);
} }
void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const void Plater::priv::show_action_buttons(const bool ready_to_slice) const
{ {
RemovableDriveManager::get_instance().set_plater_ready_to_slice(is_ready_to_slice); // Cache this value, so that the callbacks from the RemovableDriveManager may repeat that value when calling show_action_buttons().
this->ready_to_slice = ready_to_slice;
wxWindowUpdateLocker noUpdater(sidebar); wxWindowUpdateLocker noUpdater(sidebar);
const auto prin_host_opt = config->option<ConfigOptionString>("print_host"); const auto prin_host_opt = config->option<ConfigOptionString>("print_host");
const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty(); const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty();
bool disconnect_shown = !RemovableDriveManager::get_instance().is_last_drive_removed();
bool export_removable_shown = RemovableDriveManager::get_instance().get_drives_count() > 0;
// when a background processing is ON, export_btn and/or send_btn are showing // when a background processing is ON, export_btn and/or send_btn are showing
if (wxGetApp().app_config->get("background_processing") == "1") if (wxGetApp().app_config->get("background_processing") == "1")
{ {
RemovableDriveManager::RemovableDrivesStatus removable_media_status = wxGetApp().removable_drive_manager()->status();
if (sidebar->show_reslice(false) | if (sidebar->show_reslice(false) |
sidebar->show_export(true) | sidebar->show_export(true) |
sidebar->show_send(send_gcode_shown) | sidebar->show_send(send_gcode_shown) |
sidebar->show_export_removable(export_removable_shown) | sidebar->show_export_removable(removable_media_status.has_removable_drives) |
sidebar->show_disconnect(disconnect_shown)) sidebar->show_disconnect(removable_media_status.has_eject))
sidebar->Layout(); sidebar->Layout();
} }
else else
{ {
if (sidebar->show_reslice(is_ready_to_slice) | RemovableDriveManager::RemovableDrivesStatus removable_media_status;
sidebar->show_export(!is_ready_to_slice) | if (! ready_to_slice)
sidebar->show_send(send_gcode_shown && !is_ready_to_slice) | removable_media_status = wxGetApp().removable_drive_manager()->status();
sidebar->show_export_removable(export_removable_shown && !is_ready_to_slice) | if (sidebar->show_reslice(ready_to_slice) |
sidebar->show_disconnect(disconnect_shown && !is_ready_to_slice)) sidebar->show_export(!ready_to_slice) |
sidebar->show_send(send_gcode_shown && !ready_to_slice) |
sidebar->show_export_removable(!ready_to_slice && removable_media_status.has_removable_drives) |
sidebar->show_disconnect(!ready_to_slice && removable_media_status.has_eject))
sidebar->Layout(); sidebar->Layout();
} }
} }
@ -4854,51 +4912,38 @@ void Plater::export_gcode(bool prefer_removable)
return; return;
} }
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); AppConfig &appconfig = *wxGetApp().app_config;
bool removable_drives_connected = GUI::RemovableDriveManager::get_instance().update(); RemovableDriveManager &removable_drive_manager = *wxGetApp().removable_drive_manager();
if(prefer_removable) // Get a last save path, either to removable media or to an internal media.
{ std::string start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), prefer_removable);
if(removable_drives_connected) if (prefer_removable) {
{ // Returns a path to a removable media if it exists, prefering start_dir. Update the internal removable drives database.
auto start_dir_removable = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string(), true); start_dir = removable_drive_manager.get_removable_drive_path(start_dir);
if (RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir_removable)) if (start_dir.empty())
{ // Direct user to the last internal media.
start_dir = start_dir_removable; start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), false);
}else
{
start_dir = RemovableDriveManager::get_instance().get_drive_path();
}
}
} }
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")),
start_dir,
from_path(default_output_file.filename()),
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
);
fs::path output_path; fs::path output_path;
if (dlg.ShowModal() == wxID_OK) { {
fs::path path = into_path(dlg.GetPath()); wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")),
wxGetApp().app_config->update_last_output_dir(path.parent_path().string(), RemovableDriveManager::get_instance().is_path_on_removable_drive(path.parent_path().string())); start_dir,
output_path = std::move(path); from_path(default_output_file.filename()),
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
);
if (dlg.ShowModal() == wxID_OK)
output_path = into_path(dlg.GetPath());
} }
if (! output_path.empty())
{
std::string path = output_path.string();
p->export_gcode(std::move(output_path), PrintHostJob());
RemovableDriveManager::get_instance().update(0, false);
RemovableDriveManager::get_instance().set_last_save_path(path);
RemovableDriveManager::get_instance().verify_last_save_path();
if(!RemovableDriveManager::get_instance().is_last_drive_removed())
{
RemovableDriveManager::get_instance().set_is_writing(true);
RemovableDriveManager::get_instance().erase_callbacks();
RemovableDriveManager::get_instance().add_remove_callback(std::bind(&Plater::drive_ejected_callback, this));
}
if (! output_path.empty()) {
p->export_gcode(output_path, PrintHostJob());
bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string());
// Storing a path to AppConfig either as path to removable media or a path to internal media.
// is_path_on_removable_drive() is called with the "true" parameter to update its internal database as the user may have shuffled the external drives
// while the dialog was open.
appconfig.update_last_output_dir(output_path.parent_path().string(), path_on_removable_media);
p->writing_to_removable_device = path_on_removable_media;
} }
} }
@ -5220,28 +5265,11 @@ void Plater::send_gcode()
} }
} }
// Called when the Eject button is pressed.
void Plater::eject_drive() void Plater::eject_drive()
{ {
RemovableDriveManager::get_instance().update(0, true); wxGetApp().removable_drive_manager()->eject_drive();
RemovableDriveManager::get_instance().erase_callbacks();
RemovableDriveManager::get_instance().add_remove_callback(std::bind(&Plater::drive_ejected_callback, this));
RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path());
} }
void Plater::drive_ejected_callback()
{
if (RemovableDriveManager::get_instance().get_did_eject())
{
RemovableDriveManager::get_instance().set_did_eject(false);
show_info(this,
(boost::format(_utf8(L("Unmounting successful. The device %s(%s) can now be safely removed from the computer.")))
% RemovableDriveManager::get_instance().get_ejected_name()
% RemovableDriveManager::get_instance().get_ejected_path()).str());
}
p->show_action_buttons(false);
}
void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); } void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); }
void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); } void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); }
@ -5631,7 +5659,7 @@ void Plater::suppress_background_process(const bool stop_background_process)
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); } void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
void Plater::update_object_menu() { p->update_object_menu(); } void Plater::update_object_menu() { p->update_object_menu(); }
void Plater::show_action_buttons(const bool is_ready_to_slice) const { p->show_action_buttons(is_ready_to_slice); } void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); }
void Plater::copy_selection_to_clipboard() void Plater::copy_selection_to_clipboard()
{ {

View file

@ -213,7 +213,6 @@ public:
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
void send_gcode(); void send_gcode();
void eject_drive(); void eject_drive();
void drive_ejected_callback();
void take_snapshot(const std::string &snapshot_name); void take_snapshot(const std::string &snapshot_name);
void take_snapshot(const wxString &snapshot_name); void take_snapshot(const wxString &snapshot_name);

View file

@ -851,7 +851,7 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string
return preset; return preset;
} }
void PresetCollection::save_current_preset(const std::string &new_name) void PresetCollection::save_current_preset(const std::string &new_name, bool detach)
{ {
// 1) Find the preset with a new_name or create a new one, // 1) Find the preset with a new_name or create a new one,
// initialize it with the edited config. // initialize it with the edited config.
@ -866,6 +866,13 @@ void PresetCollection::save_current_preset(const std::string &new_name)
preset.config = std::move(m_edited_preset.config); preset.config = std::move(m_edited_preset.config);
// The newly saved preset will be activated -> make it visible. // The newly saved preset will be activated -> make it visible.
preset.is_visible = true; preset.is_visible = true;
if (detach) {
// Clear the link to the parent profile.
preset.vendor = nullptr;
preset.inherits().clear();
preset.alias.clear();
preset.renamed_from.clear();
}
} else { } else {
// Creating a new preset. // Creating a new preset.
Preset &preset = *m_presets.insert(it, m_edited_preset); Preset &preset = *m_presets.insert(it, m_edited_preset);
@ -874,7 +881,12 @@ void PresetCollection::save_current_preset(const std::string &new_name)
preset.name = new_name; preset.name = new_name;
preset.file = this->path_from_name(new_name); preset.file = this->path_from_name(new_name);
preset.vendor = nullptr; preset.vendor = nullptr;
if (preset.is_system) { preset.alias.clear();
preset.renamed_from.clear();
if (detach) {
// Clear the link to the parent profile.
inherits.clear();
} else if (preset.is_system) {
// Inheriting from a system preset. // Inheriting from a system preset.
inherits = /* preset.vendor->name + "/" + */ old_name; inherits = /* preset.vendor->name + "/" + */ old_name;
} else if (inherits.empty()) { } else if (inherits.empty()) {
@ -1061,6 +1073,7 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
const ConfigOption *opt = active_printer.preset.config.option("nozzle_diameter"); const ConfigOption *opt = active_printer.preset.config.option("nozzle_diameter");
if (opt) if (opt)
config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast<const ConfigOptionFloats*>(opt)->values.size())); config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast<const ConfigOptionFloats*>(opt)->values.size()));
bool some_compatible = false;
for (size_t idx_preset = m_num_default_presets; idx_preset < m_presets.size(); ++ idx_preset) { for (size_t idx_preset = m_num_default_presets; idx_preset < m_presets.size(); ++ idx_preset) {
bool selected = idx_preset == m_idx_selected; bool selected = idx_preset == m_idx_selected;
Preset &preset_selected = m_presets[idx_preset]; Preset &preset_selected = m_presets[idx_preset];
@ -1068,6 +1081,7 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
const PresetWithVendorProfile this_preset_with_vendor_profile = this->get_preset_with_vendor_profile(preset_edited); const PresetWithVendorProfile this_preset_with_vendor_profile = this->get_preset_with_vendor_profile(preset_edited);
bool was_compatible = preset_edited.is_compatible; bool was_compatible = preset_edited.is_compatible;
preset_edited.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer, &config); preset_edited.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer, &config);
some_compatible |= preset_edited.is_compatible;
if (active_print != nullptr) if (active_print != nullptr)
preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer); preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer);
if (! preset_edited.is_compatible && selected && if (! preset_edited.is_compatible && selected &&
@ -1076,6 +1090,10 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
if (selected) if (selected)
preset_selected.is_compatible = preset_edited.is_compatible; preset_selected.is_compatible = preset_edited.is_compatible;
} }
// Update visibility of the default profiles here if the defaults are suppressed, the current profile is not compatible and we don't want to select another compatible profile.
if (m_idx_selected >= m_num_default_presets && m_default_suppressed)
for (size_t i = 0; i < m_num_default_presets; ++ i)
m_presets[i].is_visible = ! some_compatible;
return m_idx_selected; return m_idx_selected;
} }

View file

@ -312,7 +312,7 @@ public:
// Save the preset under a new name. If the name is different from the old one, // Save the preset under a new name. If the name is different from the old one,
// a new preset is stored into the list of presets. // a new preset is stored into the list of presets.
// All presets are marked as not modified and the new preset is activated. // All presets are marked as not modified and the new preset is activated.
void save_current_preset(const std::string &new_name); void save_current_preset(const std::string &new_name, bool detach = false);
// Delete the current preset, activate the first visible preset. // Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully. // returns true if the preset was deleted successfully.

View file

@ -703,7 +703,10 @@ void PresetBundle::load_config_file(const std::string &path)
boost::nowide::ifstream ifs(path); boost::nowide::ifstream ifs(path);
boost::property_tree::read_ini(ifs, tree); boost::property_tree::read_ini(ifs, tree);
} catch (const std::ifstream::failure &err) { } catch (const std::ifstream::failure &err) {
throw std::runtime_error(std::string("The config file cannot be loaded: ") + path + "\n\tReason: " + err.what()); throw std::runtime_error(std::string("The Config Bundle cannot be loaded: ") + path + "\n\tReason: " + err.what());
} catch (const boost::property_tree::file_parser_error &err) {
throw std::runtime_error((boost::format("Failed loading the Config Bundle \"%1%\": %2% at line %3%")
% err.filename() % err.message() % err.line()).str());
} catch (const std::runtime_error &err) { } catch (const std::runtime_error &err) {
throw std::runtime_error(std::string("Failed loading the preset file: ") + path + "\n\tReason: " + err.what()); throw std::runtime_error(std::string("Failed loading the preset file: ") + path + "\n\tReason: " + err.what());
} }
@ -1109,8 +1112,13 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
const VendorProfile *vendor_profile = nullptr; const VendorProfile *vendor_profile = nullptr;
if (flags & (LOAD_CFGBNDLE_SYSTEM | LOAD_CFGBUNDLE_VENDOR_ONLY)) { if (flags & (LOAD_CFGBNDLE_SYSTEM | LOAD_CFGBUNDLE_VENDOR_ONLY)) {
auto vp = VendorProfile::from_ini(tree, path); auto vp = VendorProfile::from_ini(tree, path);
if (vp.num_variants() == 0) if (vp.models.size() == 0) {
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: No printer model defined.") % path;
return 0; return 0;
} else if (vp.num_variants() == 0) {
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: No printer variant defined") % path;
return 0;
}
vendor_profile = &this->vendors.insert({vp.id, vp}).first->second; vendor_profile = &this->vendors.insert({vp.id, vp}).first->second;
} }
@ -1599,21 +1607,23 @@ void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::Pre
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so // To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so
// set a bitmap height to m_bitmapLock->GetHeight() // set a bitmap height to m_bitmapLock->GetHeight()
// Note, under OSX we should use a ScaledHeight because of Retina scale //
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size.
// But for some display scaling (for example 125% or 175%) normal_icon_width differs from icon width.
// So:
// for nonsystem presets set a width of empty bitmap to m_bitmapLock->GetWidth()
// for compatible presets set a width of empty bitmap to m_bitmapIncompatible->GetWidth()
//
// Note, under OSX we should use a Scaled Height/Width because of Retina scale
#ifdef __APPLE__ #ifdef __APPLE__
const int icon_height = m_bitmapLock->GetScaledHeight(); const int icon_height = m_bitmapLock->GetScaledHeight();
const int lock_icon_width = m_bitmapLock->GetScaledWidth();
const int flag_icon_width = m_bitmapIncompatible->GetScaledWidth();
#else #else
const int icon_height = m_bitmapLock->GetHeight(); const int icon_height = m_bitmapLock->GetHeight();
#endif
/* To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size.
* But for some display scaling (for example 125% or 175%) normal_icon_width differs from icon width.
* So:
* for nonsystem presets set a width of empty bitmap to m_bitmapLock->GetWidth()
* for compatible presets set a width of empty bitmap to m_bitmapIncompatible->GetWidth()
**/
const int lock_icon_width = m_bitmapLock->GetWidth(); const int lock_icon_width = m_bitmapLock->GetWidth();
const int flag_icon_width = m_bitmapIncompatible->GetWidth(); const int flag_icon_width = m_bitmapIncompatible->GetWidth();
#endif
wxString tooltip = ""; wxString tooltip = "";

View file

@ -1,6 +1,8 @@
#include "RemovableDriveManager.hpp" #include "RemovableDriveManager.hpp"
#include <iostream> #include <libslic3r/libslic3r.h>
#include "boost/nowide/convert.hpp"
#include <boost/nowide/convert.hpp>
#include <boost/log/trivial.hpp>
#if _WIN32 #if _WIN32
#include <windows.h> #include <windows.h>
@ -9,11 +11,9 @@
#include <shlwapi.h> #include <shlwapi.h>
#include <Dbt.h> #include <Dbt.h>
GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72,
0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };
#else #else
//linux includes // unix, linux & OSX includes
#include <errno.h> #include <errno.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -26,124 +26,173 @@ GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72,
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
wxDEFINE_EVENT(EVT_REMOVABLE_DRIVE_EJECTED, RemovableDriveEjectEvent);
wxDEFINE_EVENT(EVT_REMOVABLE_DRIVES_CHANGED, RemovableDrivesChangedEvent);
#if _WIN32 #if _WIN32
/* currently not used, left for possible future use std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() const
INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
*/
void RemovableDriveManager::search_for_drives()
{ {
m_current_drives.clear();
//get logical drives flags by letter in alphabetical order //get logical drives flags by letter in alphabetical order
DWORD drives_mask = GetLogicalDrives(); DWORD drives_mask = ::GetLogicalDrives();
for (size_t i = 0; i < 26; i++)
{ // Allocate the buffers before the loop.
if(drives_mask & (1 << i)) std::wstring volume_name;
{ std::wstring file_system_name;
std::string path (1,(char)('A' + i)); // Iterate the Windows drives from 'A' to 'Z'
path+=":"; std::vector<DriveData> current_drives;
UINT drive_type = GetDriveTypeA(path.c_str()); for (size_t i = 0; i < 26; ++ i)
if (drives_mask & (1 << i)) {
std::string path { char('A' + i), ':' };
UINT drive_type = ::GetDriveTypeA(path.c_str());
// DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives) // DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives)
if (drive_type == DRIVE_REMOVABLE) if (drive_type == DRIVE_REMOVABLE) {
{
// get name of drive // get name of drive
std::wstring wpath = boost::nowide::widen(path); std::wstring wpath = boost::nowide::widen(path);
std::wstring volume_name; volume_name.resize(MAX_PATH + 1);
volume_name.resize(1024); file_system_name.resize(MAX_PATH + 1);
std::wstring file_system_name; BOOL error = ::GetVolumeInformationW(wpath.c_str(), volume_name.data(), sizeof(volume_name), nullptr, nullptr, nullptr, file_system_name.data(), sizeof(file_system_name));
file_system_name.resize(1024); if (error != 0) {
LPWSTR lp_volume_name_buffer = new wchar_t; volume_name.erase(volume_name.begin() + wcslen(volume_name.c_str()), volume_name.end());
BOOL error = GetVolumeInformationW(wpath.c_str(), &volume_name[0], sizeof(volume_name), NULL, NULL, NULL, &file_system_name[0], sizeof(file_system_name)); if (! file_system_name.empty()) {
if(error != 0)
{
volume_name.erase(std::find(volume_name.begin(), volume_name.end(), '\0'), volume_name.end());
if (file_system_name != L"")
{
ULARGE_INTEGER free_space; ULARGE_INTEGER free_space;
GetDiskFreeSpaceExA(path.c_str(), &free_space, NULL, NULL); ::GetDiskFreeSpaceExA(path.c_str(), &free_space, nullptr, nullptr);
if (free_space.QuadPart > 0) if (free_space.QuadPart > 0) {
{
path += "\\"; path += "\\";
m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); current_drives.emplace_back(DriveData{ boost::nowide::narrow(volume_name), path });
} }
} }
} }
} }
} }
return current_drives;
}
// Called from UI therefore it blocks the UI thread.
// It also blocks updates at the worker thread.
// Win32 implementation.
void RemovableDriveManager::eject_drive()
{
if (m_last_save_path.empty())
return;
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this->update();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
tbb::mutex::scoped_lock lock(m_drives_mutex);
auto it_drive_data = this->find_last_save_path_drive_data();
if (it_drive_data != m_current_drives.end()) {
// get handle to device
std::string mpath = "\\\\.\\" + m_last_save_path;
mpath = mpath.substr(0, mpath.size() - 1);
HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE) {
std::cerr << "Ejecting " << mpath << " failed " << GetLastError() << " \n";
return;
}
DWORD deviceControlRetVal(0);
//these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger.
//sd cards does trigger WM_DEVICECHANGE messege, usb drives dont
DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
// some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here but it returns error to me
BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
if (error == 0) {
CloseHandle(handle);
BOOST_LOG_TRIVIAL(error) << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n";
return;
}
CloseHandle(handle);
assert(m_callback_evt_handler);
if (m_callback_evt_handler)
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::move(*it_drive_data)));
m_current_drives.erase(it_drive_data);
} }
} }
void RemovableDriveManager::eject_drive(const std::string &path)
{
if(m_current_drives.empty())
return;
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
{
if ((*it).path == path)
{
// get handle to device
std::string mpath = "\\\\.\\" + path;
mpath = mpath.substr(0, mpath.size() - 1);
HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE)
{
std::cerr << "Ejecting " << mpath << " failed " << GetLastError() << " \n";
return;
}
DWORD deviceControlRetVal(0);
//these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger.
//sd cards does trigger WM_DEVICECHANGE messege, usb drives dont
DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); std::string RemovableDriveManager::get_removable_drive_path(const std::string &path)
DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); {
// some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here but it returns error to me #ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); this->update();
if (error == 0) #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
{
CloseHandle(handle); tbb::mutex::scoped_lock lock(m_drives_mutex);
std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; if (m_current_drives.empty())
return; return std::string();
} std::size_t found = path.find_last_of("\\");
CloseHandle(handle); std::string new_path = path.substr(0, found);
m_did_eject = true; int letter = PathGetDriveNumberA(new_path.c_str());
m_current_drives.erase(it); for (const DriveData &drive_data : m_current_drives) {
m_ejected_path = m_last_save_path; char drive = drive_data.path[0];
m_ejected_name = m_last_save_name; if (drive == 'A' + letter)
break; return path;
}
return m_current_drives.front().path;
}
std::string RemovableDriveManager::get_removable_drive_from_path(const std::string& path)
{
tbb::mutex::scoped_lock lock(m_drives_mutex);
std::size_t found = path.find_last_of("\\");
std::string new_path = path.substr(0, found);
int letter = PathGetDriveNumberA(new_path.c_str());
for (const DriveData &drive_data : m_current_drives) {
assert(! drive_data.path.empty());
if (drive_data.path.front() == 'A' + letter)
return drive_data.path;
}
return std::string();
}
#if 0
// currently not used, left for possible future use
INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// here we need to catch messeges about device removal
// problem is that when ejecting usb (how is it implemented above) there is no messege dispached. Only after physical removal of the device.
//uncomment register_window() in init() to register and comment update() in GUI_App.cpp (only for windows!) to stop recieving periodical updates
LRESULT lRet = 1;
static HDEVNOTIFY hDeviceNotify;
static constexpr GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };
switch (message)
{
case WM_CREATE:
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = WceusbshGUID;
hDeviceNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
break;
case WM_DEVICECHANGE:
{
// here is the important
if(wParam == DBT_DEVICEREMOVECOMPLETE)
{
RemovableDriveManager::get_instance().update(0, true);
} }
} }
} break;
bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path)
{ default:
if (m_current_drives.empty()) // Send all other messages on to the default windows handler.
return false; lRet = DefWindowProc(hWnd, message, wParam, lParam);
std::size_t found = path.find_last_of("\\"); break;
std::string new_path = path.substr(0, found);
int letter = PathGetDriveNumberA(new_path.c_str());
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
{
char drive = (*it).path[0];
if (drive == ('A' + letter))
return true;
} }
return false; return lRet;
}
std::string RemovableDriveManager::get_drive_from_path(const std::string& path)
{
std::size_t found = path.find_last_of("\\");
std::string new_path = path.substr(0, found);
int letter = PathGetDriveNumberA(new_path.c_str());
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
{
char drive = (*it).path[0];
if (drive == ('A' + letter))
return (*it).path;
}
return "";
} }
void RemovableDriveManager::register_window() void RemovableDriveManager::register_window()
{ {
//creates new unvisible window that is recieving callbacks from system //creates new unvisible window that is recieving callbacks from system
// structure to register // structure to register
/* currently not used, left for possible future use // currently not used, left for possible future use
WNDCLASSEX wndClass; WNDCLASSEX wndClass;
wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
@ -179,432 +228,288 @@ void RemovableDriveManager::register_window()
} }
//ShowWindow(hWnd, SW_SHOWNORMAL); //ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd); UpdateWindow(hWnd);
*/
} }
/* currently not used, left for possible future use #endif
INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
#else
namespace search_for_drives_internal
{ {
// here we need to catch messeges about device removal static bool compare_filesystem_id(const std::string &path_a, const std::string &path_b)
// problem is that when ejecting usb (how is it implemented above) there is no messege dispached. Only after physical removal of the device.
//uncomment register_window() in init() to register and comment update() in GUI_App.cpp (only for windows!) to stop recieving periodical updates
LRESULT lRet = 1;
static HDEVNOTIFY hDeviceNotify;
switch (message)
{ {
case WM_CREATE: struct stat buf;
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; stat(path_a.c_str() ,&buf);
dev_t id_a = buf.st_dev;
stat(path_b.c_str() ,&buf);
dev_t id_b = buf.st_dev;
return id_a == id_b;
}
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); void inspect_file(const std::string &path, const std::string &parent_path, std::vector<DriveData> &out)
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = WceusbshGUID;
hDeviceNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
break;
case WM_DEVICECHANGE:
{ {
// here is the important //confirms if the file is removable drive and adds it to vector
if(wParam == DBT_DEVICEREMOVECOMPLETE)
{ //if not same file system - could be removable drive
- RemovableDriveManager::get_instance().update(0, true); if (! compare_filesystem_id(path, parent_path)) {
//free space
boost::filesystem::space_info si = boost::filesystem::space(path);
if (si.available != 0) {
//user id
struct stat buf;
stat(path.c_str(), &buf);
uid_t uid = buf.st_uid;
std::string username(std::getenv("USER"));
struct passwd *pw = getpwuid(uid);
if (pw != 0 && pw->pw_name == username)
out.emplace_back(DriveData{ boost::filesystem::basename(boost::filesystem::path(path)), path });
}
} }
} }
break;
default: static void search_path(const std::string &path, const std::string &parent_path, std::vector<DriveData> &out)
// Send all other messages on to the default windows handler. {
lRet = DefWindowProc(hWnd, message, wParam, lParam); glob_t globbuf;
break; globbuf.gl_offs = 2;
int error = glob(path.c_str(), GLOB_TILDE, NULL, &globbuf);
if (error == 0) {
for (size_t i = 0; i < globbuf.gl_pathc; ++ i)
inspect_file(globbuf.gl_pathv[i], parent_path, out);
} else {
//if error - path probably doesnt exists so function just exits
//std::cout<<"glob error "<< error<< "\n";
}
globfree(&globbuf);
} }
return lRet;
} }
*/
#else
void RemovableDriveManager::search_for_drives()
{
m_current_drives.clear(); std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() const
{
std::vector<DriveData> current_drives;
#if __APPLE__ #if __APPLE__
// if on macos obj-c class will enumerate
if(m_rdmmm) this->list_devices(current_drives);
{
m_rdmmm->list_devices();
}
#else #else
//search /media/* folder //search /media/* folder
search_path("/media/*", "/media"); search_for_drives_internal::search_path("/media/*", "/media", current_drives);
//search_path("/Volumes/*", "/Volumes"); //search_path("/Volumes/*", "/Volumes");
std::string path(std::getenv("USER")); std::string path(std::getenv("USER"));
std::string pp(path); std::string pp(path);
{ //search /media/USERNAME/* folder
//search /media/USERNAME/* folder pp = "/media/"+pp;
pp = "/media/"+pp; path = "/media/" + path + "/*";
path = "/media/" + path + "/*"; search_for_drives_internal::search_path(path, pp, current_drives);
search_path(path, pp);
//search /run/media/USERNAME/* folder //search /run/media/USERNAME/* folder
path = "/run" + path; path = "/run" + path;
pp = "/run"+pp; pp = "/run"+pp;
search_path(path, pp); search_for_drives_internal::search_path(path, pp, current_drives);
}
#endif #endif
}
void RemovableDriveManager::search_path(const std::string &path,const std::string &parent_path)
{
glob_t globbuf;
globbuf.gl_offs = 2;
int error = glob(path.c_str(), GLOB_TILDE, NULL, &globbuf);
if(error == 0)
{
for(size_t i = 0; i < globbuf.gl_pathc; i++)
{
inspect_file(globbuf.gl_pathv[i], parent_path);
}
}else
{
//if error - path probably doesnt exists so function just exits
//std::cout<<"glob error "<< error<< "\n";
}
globfree(&globbuf); return current_drives;
} }
void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path)
{
//confirms if the file is removable drive and adds it to vector
//if not same file system - could be removable drive // Called from UI therefore it blocks the UI thread.
if(!compare_filesystem_id(path, parent_path)) // It also blocks updates at the worker thread.
{ // Unix & OSX implementation.
//free space void RemovableDriveManager::eject_drive()
boost::filesystem::space_info si = boost::filesystem::space(path);
if(si.available != 0)
{
//user id
struct stat buf;
stat(path.c_str(), &buf);
uid_t uid = buf.st_uid;
std::string username(std::getenv("USER"));
struct passwd *pw = getpwuid(uid);
if (pw != 0 && pw->pw_name == username)
m_current_drives.push_back(DriveData(boost::filesystem::basename(boost::filesystem::path(path)), path));
}
}
}
bool RemovableDriveManager::compare_filesystem_id(const std::string &path_a, const std::string &path_b)
{ {
struct stat buf; if (m_last_save_path.empty())
stat(path_a.c_str() ,&buf);
dev_t id_a = buf.st_dev;
stat(path_b.c_str() ,&buf);
dev_t id_b = buf.st_dev;
return id_a == id_b;
}
void RemovableDriveManager::eject_drive(const std::string &path)
{
if (m_current_drives.empty())
return; return;
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) #ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
{ this->update();
if((*it).path == path) #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
{
std::string correct_path(path); tbb::mutex::scoped_lock lock(m_drives_mutex);
for (size_t i = 0; i < correct_path.size(); ++i) auto it_drive_data = this->find_last_save_path_drive_data();
{ if (it_drive_data != m_current_drives.end()) {
if(correct_path[i]==' ') std::string correct_path(m_last_save_path);
{ for (size_t i = 0; i < correct_path.size(); ++i)
correct_path = correct_path.insert(i,1,'\\'); if (correct_path[i]==' ') {
i++; correct_path = correct_path.insert(i,1,'\\');
} ++ i;
} }
//std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n"; //std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
// there is no usable command in c++ so terminal command is used instead // there is no usable command in c++ so terminal command is used instead
// but neither triggers "succesful safe removal messege" // but neither triggers "succesful safe removal messege"
std::string command = ""; std::string command =
#if __APPLE__ #if __APPLE__
//m_rdmmm->eject_device(path); //this->eject_device(m_last_save_path);
command = "diskutil unmount "; "diskutil unmount ";
#else #else
command = "umount "; "umount ";
#endif #endif
command += correct_path; command += correct_path;
int err = system(command.c_str()); int err = system(command.c_str());
if(err) if (err) {
{ BOOST_LOG_TRIVIAL(error) << "Ejecting " << m_last_save_path << " failed";
std::cerr<<"Ejecting failed\n"; return;
return;
}
m_did_eject = true;
m_current_drives.erase(it);
m_ejected_path = m_last_save_path;
m_ejected_name = m_last_save_name;
break;
} }
assert(m_callback_evt_handler);
if (m_callback_evt_handler)
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::move(*it_drive_data)));
m_current_drives.erase(it_drive_data);
} }
}
} std::string RemovableDriveManager::get_removable_drive_path(const std::string &path)
bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path)
{
if (m_current_drives.empty())
return false;
std::size_t found = path.find_last_of("/");
std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path;
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
{
if(compare_filesystem_id(new_path, (*it).path))
return true;
}
return false;
}
std::string RemovableDriveManager::get_drive_from_path(const std::string& path)
{ {
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this->update();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
std::size_t found = path.find_last_of("/"); std::size_t found = path.find_last_of("/");
std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path; std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path;
tbb::mutex::scoped_lock lock(m_drives_mutex);
for (const DriveData &data : m_current_drives)
if (search_for_drives_internal::compare_filesystem_id(new_path, data.path))
return path;
return m_current_drives.empty() ? std::string() : m_current_drives.front().path;
}
std::string RemovableDriveManager::get_removable_drive_from_path(const std::string& path)
{
std::size_t found = path.find_last_of("/");
std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path;
// trim the filename // trim the filename
found = new_path.find_last_of("/"); found = new_path.find_last_of("/");
new_path = new_path.substr(0, found); new_path = new_path.substr(0, found);
//check if same filesystem // check if same filesystem
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) tbb::mutex::scoped_lock lock(m_drives_mutex);
{ for (const DriveData &drive_data : m_current_drives)
if (compare_filesystem_id(new_path, (*it).path)) if (search_for_drives_internal::compare_filesystem_id(new_path, drive_data.path))
return (*it).path; return drive_data.path;
} return std::string();
return "";
} }
#endif #endif
RemovableDriveManager::RemovableDriveManager(): void RemovableDriveManager::init(wxEvtHandler *callback_evt_handler)
m_drives_count(0),
m_last_update(0),
m_last_save_path(""),
m_last_save_name(""),
m_last_save_path_verified(false),
m_is_writing(false),
m_did_eject(false),
m_plater_ready_to_slice(true),
m_ejected_path(""),
m_ejected_name("")
#if __APPLE__
, m_rdmmm(new RDMMMWrapper())
#endif
{}
RemovableDriveManager::~RemovableDriveManager()
{ {
#if __APPLE__ assert(! m_initialized);
delete m_rdmmm; assert(m_callback_evt_handler == nullptr);
#endif
} if (m_initialized)
void RemovableDriveManager::init() return;
{
//add_callback([](void) { RemovableDriveManager::get_instance().print(); }); m_initialized = true;
m_callback_evt_handler = callback_evt_handler;
#if _WIN32 #if _WIN32
//register_window(); //this->register_window_msw();
#elif __APPLE__ #elif __APPLE__
m_rdmmm->register_window(); this->register_window_osx();
#endif #endif
update(0, true);
} #ifdef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
bool RemovableDriveManager::update(const long time,const bool check) this->update();
{ #else // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
if(time != 0) //time = 0 is forced update // Don't call update() manually, as the UI triggered APIs call this->update() anyways.
{ m_thread = boost::thread((boost::bind(&RemovableDriveManager::thread_proc, this)));
long diff = m_last_update - time; #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
if(diff <= -2)
{
m_last_update = time;
}else
{
return false; // return value shouldnt matter if update didnt run
}
}
search_for_drives();
if (m_drives_count != m_current_drives.size())
{
if (check)
{
check_and_notify();
}
m_drives_count = m_current_drives.size();
}
return !m_current_drives.empty();
} }
bool RemovableDriveManager::is_drive_mounted(const std::string &path) const void RemovableDriveManager::shutdown()
{ {
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) #ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
{ if (m_thread.joinable()) {
if ((*it).path == path) // Stop the worker thread, if running.
{ {
return true; // Notify the worker thread to cancel wait on detection polling.
std::lock_guard<std::mutex> lck(m_thread_stop_mutex);
m_stop = true;
} }
m_thread_stop_condition.notify_all();
// Wait for the worker thread to stop.
m_thread.join();
m_stop = false;
} }
return false; #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
#if _WIN32
//this->unregister_window_msw();
#elif __APPLE__
this->unregister_window_osx();
#endif
m_initialized = false;
m_callback_evt_handler = nullptr;
} }
std::string RemovableDriveManager::get_drive_path()
bool RemovableDriveManager::set_and_verify_last_save_path(const std::string &path)
{ {
if (m_current_drives.size() == 0) #ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this->update();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
m_last_save_path = this->get_removable_drive_from_path(path);
return ! m_last_save_path.empty();
}
RemovableDriveManager::RemovableDrivesStatus RemovableDriveManager::status()
{
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this->update();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
RemovableDriveManager::RemovableDrivesStatus out;
{ {
reset_last_save_path(); tbb::mutex::scoped_lock lock(m_drives_mutex);
return ""; out.has_eject = this->find_last_save_path_drive_data() != m_current_drives.end();
out.has_removable_drives = ! m_current_drives.empty();
} }
if (m_last_save_path_verified) if (! out.has_eject)
return m_last_save_path; m_last_save_path.clear();
return m_current_drives.back().path; return out;
} }
std::string RemovableDriveManager::get_last_save_path() const
// Update is called from thread_proc() and from most of the public methods on demand.
void RemovableDriveManager::update()
{ {
if (!m_last_save_path_verified) std::vector<DriveData> current_drives = this->search_for_removable_drives();
return "";
return m_last_save_path; // Post update events.
} tbb::mutex::scoped_lock lock(m_drives_mutex);
std::string RemovableDriveManager::get_last_save_name() const std::sort(current_drives.begin(), current_drives.end());
{ if (current_drives != m_current_drives) {
return m_last_save_name; assert(m_callback_evt_handler);
} if (m_callback_evt_handler)
std::vector<DriveData> RemovableDriveManager::get_all_drives() const wxPostEvent(m_callback_evt_handler, RemovableDrivesChangedEvent(EVT_REMOVABLE_DRIVES_CHANGED));
{
return m_current_drives;
}
void RemovableDriveManager::check_and_notify()
{
if(m_drive_count_changed_callback)
{
m_drive_count_changed_callback(m_plater_ready_to_slice);
} }
if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && !is_drive_mounted(m_last_save_path)) m_current_drives = std::move(current_drives);
{ }
for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it)
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
void RemovableDriveManager::thread_proc()
{
for (;;) {
// Wait for 2 seconds before running the disk enumeration.
// Cancellable.
{ {
(*it)(); std::unique_lock<std::mutex> lck(m_thread_stop_mutex);
m_thread_stop_condition.wait_for(lck, std::chrono::seconds(2), [this]{ return m_stop; });
} }
if (m_stop)
// Stop the worker thread.
break;
// Update m_current drives and send out update events.
this->update();
} }
} }
void RemovableDriveManager::add_remove_callback(std::function<void()> callback) #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
std::vector<DriveData>::const_iterator RemovableDriveManager::find_last_save_path_drive_data() const
{ {
m_callbacks.push_back(callback); return Slic3r::binary_find_by_predicate(m_current_drives.begin(), m_current_drives.end(),
[this](const DriveData &data){ return data.path < m_last_save_path; },
[this](const DriveData &data){ return data.path == m_last_save_path; });
} }
void RemovableDriveManager::erase_callbacks()
{ }} // namespace Slic3r::GUI
m_callbacks.clear();
}
void RemovableDriveManager::set_drive_count_changed_callback(std::function<void(const bool)> callback)
{
m_drive_count_changed_callback = callback;
}
void RemovableDriveManager::set_plater_ready_to_slice(bool b)
{
m_plater_ready_to_slice = b;
}
void RemovableDriveManager::set_last_save_path(const std::string& path)
{
if(m_last_save_path_verified)// if old path is on drive
{
if(get_drive_from_path(path) != "") //and new is too, rewrite the path
{
m_last_save_path_verified = false;
m_last_save_path = path;
}//else do nothing
}else
{
m_last_save_path = path;
}
}
void RemovableDriveManager::verify_last_save_path()
{
std::string last_drive = get_drive_from_path(m_last_save_path);
if (last_drive != "")
{
m_last_save_path_verified = true;
m_last_save_path = last_drive;
m_last_save_name = get_drive_name(last_drive);
}else
{
reset_last_save_path();
}
}
std::string RemovableDriveManager::get_drive_name(const std::string& path) const
{
if (m_current_drives.size() == 0)
return "";
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
{
if ((*it).path == path)
{
return (*it).name;
}
}
return "";
}
bool RemovableDriveManager::is_last_drive_removed()
{
if(!m_last_save_path_verified)
{
return true;
}
bool r = !is_drive_mounted(m_last_save_path);
if (r)
{
reset_last_save_path();
}
return r;
}
bool RemovableDriveManager::is_last_drive_removed_with_update(const long time)
{
update(time, false);
return is_last_drive_removed();
}
void RemovableDriveManager::reset_last_save_path()
{
m_last_save_path_verified = false;
m_last_save_path = "";
m_last_save_name = "";
}
void RemovableDriveManager::set_is_writing(const bool b)
{
m_is_writing = b;
if (b)
{
m_did_eject = false;
}
}
bool RemovableDriveManager::get_is_writing() const
{
return m_is_writing;
}
bool RemovableDriveManager::get_did_eject() const
{
return m_did_eject;
}
void RemovableDriveManager::set_did_eject(const bool b)
{
m_did_eject = b;
}
size_t RemovableDriveManager::get_drives_count() const
{
return m_current_drives.size();
}
std::string RemovableDriveManager::get_ejected_path() const
{
return m_ejected_path;
}
std::string RemovableDriveManager::get_ejected_name() const
{
return m_ejected_name;
}
}}//namespace Slicer::Gui

View file

@ -3,119 +3,127 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <functional>
#include <boost/thread.hpp>
#include <tbb/mutex.h>
#include <condition_variable>
// Custom wxWidget events
#include "Event.hpp"
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#if __APPLE__
class RDMMMWrapper;
#endif
struct DriveData struct DriveData
{ {
std::string name; std::string name;
std::string path; std::string path;
DriveData(std::string n, std::string p):name(n),path(p){}
void clear() {
name.clear();
path.clear();
}
bool empty() const {
return path.empty();
}
}; };
inline bool operator< (const DriveData &lhs, const DriveData &rhs) { return lhs.path < rhs.path; }
inline bool operator> (const DriveData &lhs, const DriveData &rhs) { return lhs.path > rhs.path; }
inline bool operator==(const DriveData &lhs, const DriveData &rhs) { return lhs.path == rhs.path; }
using RemovableDriveEjectEvent = Event<DriveData>;
wxDECLARE_EVENT(EVT_REMOVABLE_DRIVE_EJECTED, RemovableDriveEjectEvent);
using RemovableDrivesChangedEvent = SimpleEvent;
wxDECLARE_EVENT(EVT_REMOVABLE_DRIVES_CHANGED, RemovableDrivesChangedEvent);
#if __APPLE__
// Callbacks on device plug / unplug work reliably on OSX.
#define REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
#endif // __APPLE__
class RemovableDriveManager class RemovableDriveManager
{ {
#if __APPLE__
friend class RDMMMWrapper;
#endif
public: public:
static RemovableDriveManager& get_instance() RemovableDriveManager() = default;
{
static RemovableDriveManager instance;
return instance;
}
RemovableDriveManager(RemovableDriveManager const&) = delete; RemovableDriveManager(RemovableDriveManager const&) = delete;
void operator=(RemovableDriveManager const&) = delete; void operator=(RemovableDriveManager const&) = delete;
~RemovableDriveManager(); ~RemovableDriveManager() { assert(! m_initialized); }
//call only once. on apple register for unmnount callbacks. on windows register for device notification is prepared but not called (eject usb drive on widnows doesnt trigger the callback, sdc ard does), also enumerates devices for first time so init shoud be called on linux too.
void init(); // Start the background thread and register this window as a target for update events.
//update() searches for removable devices, returns false if empty. /time = 0 is forced update, time expects wxGetLocalTime() // Register for OSX notifications.
bool update(const long time = 0,const bool check = false); void init(wxEvtHandler *callback_evt_handler);
bool is_drive_mounted(const std::string &path) const; // Stop the background thread of the removable drive manager, so that no new updates will be sent out.
void eject_drive(const std::string &path); // Deregister OSX notifications.
//returns path to last drive which was used, if none was used, returns device that was enumerated last void shutdown();
std::string get_last_save_path() const;
std::string get_last_save_name() const; // Returns path to a removable media if it exists, prefering the input path.
//returns path to last drive which was used, if none was used, returns empty string std::string get_removable_drive_path(const std::string &path);
std::string get_drive_path(); bool is_path_on_removable_drive(const std::string &path) { return this->get_removable_drive_path(path) == path; }
std::vector<DriveData> get_all_drives() const;
bool is_path_on_removable_drive(const std::string &path); // Verify whether the path provided is on removable media. If so, save the path for further eject and return true, otherwise return false.
// callback will notify only if device with last save path was removed bool set_and_verify_last_save_path(const std::string &path);
void add_remove_callback(std::function<void()> callback); // Eject drive of a file set by set_and_verify_last_save_path().
// erases all remove callbacks added by add_remove_callback() // On Unix / OSX, the function blocks and sends out the EVT_REMOVABLE_DRIVE_EJECTED event on success.
void erase_callbacks(); // On Windows, the function does not block, and the eject is detected in the background thread.
//drive_count_changed callback is called on every added or removed device void eject_drive();
void set_drive_count_changed_callback(std::function<void(const bool)> callback);
//thi serves to set correct value for drive_count_changed callback struct RemovableDrivesStatus {
void set_plater_ready_to_slice(bool b); bool has_removable_drives { false };
// marks one of the eveices in vector as last used bool has_eject { false };
void set_last_save_path(const std::string &path); };
void verify_last_save_path(); RemovableDrivesStatus status();
bool is_last_drive_removed();
// param as update() // Enumerates current drives and sends out wxWidget events on change or eject.
bool is_last_drive_removed_with_update(const long time = 0); // Called by each public method, by the background thread and from RemovableDriveManagerMM::on_device_unmount OSX notification handler.
void set_is_writing(const bool b); // Not to be called manually.
bool get_is_writing() const; // Public to be accessible from RemovableDriveManagerMM::on_device_unmount OSX notification handler.
bool get_did_eject() const; // It would be better to make this method private and friend to RemovableDriveManagerMM, but RemovableDriveManagerMM is an ObjectiveC class.
void set_did_eject(const bool b); void update();
std::string get_drive_name(const std::string& path) const;
size_t get_drives_count() const; private:
std::string get_ejected_path() const; bool m_initialized { false };
std::string get_ejected_name() const; wxEvtHandler* m_callback_evt_handler { nullptr };
private:
RemovableDriveManager(); #ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
void search_for_drives(); // Worker thread, worker thread synchronization and callbacks to the UI thread.
//triggers callbacks if last used drive was removed void thread_proc();
void check_and_notify(); boost::thread m_thread;
//returns drive path (same as path in DriveData) if exists otherwise empty string "" std::condition_variable m_thread_stop_condition;
std::string get_drive_from_path(const std::string& path); mutable std::mutex m_thread_stop_mutex;
void reset_last_save_path(); bool m_stop { false };
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
// Called from update() to enumerate removable drives.
std::vector<DriveData> search_for_removable_drives() const;
// m_current_drives is guarded by m_drives_mutex
// sorted ascending by path
std::vector<DriveData> m_current_drives;
mutable tbb::mutex m_drives_mutex;
// Returns drive path (same as path in DriveData) if exists otherwise empty string.
std::string get_removable_drive_from_path(const std::string& path);
// Returns iterator to a drive in m_current_drives with path equal to m_last_save_path or end().
std::vector<DriveData>::const_iterator find_last_save_path_drive_data() const;
// Set with set_and_verify_last_save_path() to a removable drive path to be ejected.
std::string m_last_save_path;
std::vector<DriveData> m_current_drives;
std::vector<std::function<void()>> m_callbacks;
std::function<void(const bool)> m_drive_count_changed_callback;
size_t m_drives_count;
long m_last_update;
std::string m_last_save_path;
bool m_last_save_path_verified;
std::string m_last_save_name;
bool m_is_writing;//on device
bool m_did_eject;
bool m_plater_ready_to_slice;
std::string m_ejected_path;
std::string m_ejected_name;
#if _WIN32 #if _WIN32
//registers for notifications by creating invisible window //registers for notifications by creating invisible window
void register_window(); //void register_window_msw();
#else #elif __APPLE__
#if __APPLE__ void register_window_osx();
RDMMMWrapper * m_rdmmm; void unregister_window_osx();
#endif void list_devices(std::vector<DriveData> &out) const;
void search_path(const std::string &path, const std::string &parent_path); // not used as of now
bool compare_filesystem_id(const std::string &path_a, const std::string &path_b);
void inspect_file(const std::string &path, const std::string &parent_path);
#endif
};
// apple wrapper for RemovableDriveManagerMM which searches for drives and/or ejects them
#if __APPLE__
class RDMMMWrapper
{
public:
RDMMMWrapper();
~RDMMMWrapper();
void register_window();
void list_devices();
void eject_device(const std::string &path); void eject_device(const std::string &path);
void log(const std::string &msg); // Opaque pointer to RemovableDriveManagerMM
protected: void *m_impl_osx;
void *m_imp; #endif
//friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path);
}; };
#endif
}}
#endif
}}
#endif // slic3r_GUI_RemovableDriveManager_hpp_

View file

@ -1,5 +1,6 @@
#import "RemovableDriveManager.hpp" #import "RemovableDriveManager.hpp"
#import "RemovableDriveManagerMM.h" #import "RemovableDriveManagerMM.h"
#import "GUI_App.hpp"
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
#import <DiskArbitration/DiskArbitration.h> #import <DiskArbitration/DiskArbitration.h>
@ -10,22 +11,23 @@
-(instancetype) init -(instancetype) init
{ {
self = [super init]; self = [super init];
if(self) //if(self){}
{
}
return self; return self;
} }
-(void) on_device_unmount: (NSNotification*) notification -(void) on_device_unmount: (NSNotification*) notification
{ {
NSLog(@"on device change"); //NSLog(@"on device change");
Slic3r::GUI::RemovableDriveManager::get_instance().update(0,true); Slic3r::GUI::wxGetApp().removable_drive_manager()->update();
} }
-(void) add_unmount_observer -(void) add_unmount_observer
{ {
NSLog(@"add unmount observer"); //NSLog(@"add unmount observer");
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidMountNotification object:nil]; [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidMountNotification object:nil];
} }
-(NSArray*) list_dev -(NSArray*) list_dev
{ {
// DEPRICATED: // DEPRICATED:
@ -40,118 +42,99 @@
DADiskRef disk; DADiskRef disk;
DASessionRef session; DASessionRef session;
CFDictionaryRef descDict; CFDictionaryRef descDict;
session = DASessionCreate(NULL); session = DASessionCreate(nullptr);
if (session == NULL) { if (session == nullptr)
err = EINVAL; err = EINVAL;
}
if (err == 0) { if (err == 0) {
disk = DADiskCreateFromVolumePath(NULL,session,(CFURLRef)volURL); disk = DADiskCreateFromVolumePath(nullptr,session,(CFURLRef)volURL);
if (session == NULL) { if (session == nullptr)
err = EINVAL; err = EINVAL;
}
} }
if (err == 0) { if (err == 0) {
descDict = DADiskCopyDescription(disk); descDict = DADiskCopyDescription(disk);
if (descDict == NULL) { if (descDict == nullptr)
err = EINVAL; err = EINVAL;
}
} }
if (err == 0) { if (err == 0) {
CFTypeRef mediaEjectableKey = CFDictionaryGetValue(descDict,kDADiskDescriptionMediaEjectableKey); CFTypeRef mediaEjectableKey = CFDictionaryGetValue(descDict,kDADiskDescriptionMediaEjectableKey);
BOOL ejectable = [mediaEjectableKey boolValue]; BOOL ejectable = [mediaEjectableKey boolValue];
CFTypeRef deviceProtocolName = CFDictionaryGetValue(descDict,kDADiskDescriptionDeviceProtocolKey); CFTypeRef deviceProtocolName = CFDictionaryGetValue(descDict,kDADiskDescriptionDeviceProtocolKey);
CFTypeRef deviceModelKey = CFDictionaryGetValue(descDict, kDADiskDescriptionDeviceModelKey); CFTypeRef deviceModelKey = CFDictionaryGetValue(descDict, kDADiskDescriptionDeviceModelKey);
if (mediaEjectableKey != NULL) if (mediaEjectableKey != nullptr) {
{
BOOL op = ejectable && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceModelKey, CFSTR("SD Card Reader"))); BOOL op = ejectable && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceModelKey, CFSTR("SD Card Reader")));
//!CFEqual(deviceModelKey, CFSTR("Disk Image")); //!CFEqual(deviceModelKey, CFSTR("Disk Image"));
// if (op)
if (op) {
[result addObject:volURL.path]; [result addObject:volURL.path];
}
} }
} }
if (descDict != NULL) { if (descDict != nullptr)
CFRelease(descDict); CFRelease(descDict);
}
} }
return result; return result;
} }
//this eject drive is not used now
-(void)eject_drive:(NSString *)path -(void)eject_drive:(NSString *)path
{ {
DADiskRef disk; DADiskRef disk;
DASessionRef session; DASessionRef session;
NSURL *url = [[NSURL alloc] initFileURLWithPath:path]; NSURL *url = [[NSURL alloc] initFileURLWithPath:path];
int err = 0; int err = 0;
session = DASessionCreate(NULL); session = DASessionCreate(nullptr);
if (session == NULL) { if (session == nullptr)
err = EINVAL; err = EINVAL;
} if (err == 0)
if (err == 0) { disk = DADiskCreateFromVolumePath(nullptr,session,(CFURLRef)url);
disk = DADiskCreateFromVolumePath(NULL,session,(CFURLRef)url);
}
if( err == 0) if( err == 0)
{ DADiskUnmount(disk, kDADiskUnmountOptionDefault, nullptr, nullptr);
DADiskUnmount(disk, kDADiskUnmountOptionDefault, if (disk != nullptr)
NULL, NULL);
}
if (disk != NULL) {
CFRelease(disk); CFRelease(disk);
} if (session != nullptr)
if (session != NULL) {
CFRelease(session); CFRelease(session);
}
} }
namespace Slic3r {
namespace GUI {
RDMMMWrapper::RDMMMWrapper():m_imp(nullptr){
m_imp = [[RemovableDriveManagerMM alloc] init];
}
RDMMMWrapper::~RDMMMWrapper()
{
if(m_imp)
{
[m_imp release];
}
}
void RDMMMWrapper::register_window()
{
if(m_imp)
{
[m_imp add_unmount_observer];
}
}
void RDMMMWrapper::list_devices()
{
if(m_imp)
{
NSArray* devices = [m_imp list_dev];
for (NSString* volumePath in devices)
{
NSLog(@"%@", volumePath);
Slic3r::GUI::RemovableDriveManager::get_instance().inspect_file(std::string([volumePath UTF8String]), "/Volumes");
}
}
}
void RDMMMWrapper::log(const std::string &msg)
{
NSLog(@"%s", msg.c_str());
}
void RDMMMWrapper::eject_device(const std::string &path)
{
if(m_imp)
{
NSString * pth = [NSString stringWithCString:path.c_str()
encoding:[NSString defaultCStringEncoding]];
[m_imp eject_drive:pth];
}
}
}}//namespace Slicer::GUI
/*
*/
@end @end
namespace Slic3r {
namespace GUI {
void RemovableDriveManager::register_window_osx()
{
assert(m_impl_osx == nullptr);
m_impl_osx = [[RemovableDriveManagerMM alloc] init];
if (m_impl_osx)
[m_impl_osx add_unmount_observer];
}
void RemovableDriveManager::unregister_window_osx()
{
if (m_impl_osx)
[m_impl_osx release];
}
namespace search_for_drives_internal
{
void inspect_file(const std::string &path, const std::string &parent_path, std::vector<DriveData> &out);
}
void RemovableDriveManager::list_devices(std::vector<DriveData> &out) const
{
assert(m_impl_osx != nullptr);
if (m_impl_osx) {
NSArray* devices = [m_impl_osx list_dev];
for (NSString* volumePath in devices)
search_for_drives_internal::inspect_file(std::string([volumePath UTF8String]), "/Volumes", out);
}
}
// not used as of now
void RemovableDriveManager::eject_device(const std::string &path)
{
assert(m_impl_osx != nullptr);
if (m_impl_osx) {
NSString * pth = [NSString stringWithCString:path.c_str() encoding:[NSString defaultCStringEncoding]];
[m_impl_osx eject_drive:pth];
}
}
}}//namespace Slicer::GUI

View file

@ -359,9 +359,10 @@ void Tab::update_labels_colour()
color = &m_modified_label_clr; color = &m_modified_label_clr;
} }
if (opt.first == "bed_shape" || opt.first == "compatible_prints" || opt.first == "compatible_printers") { if (opt.first == "bed_shape" || opt.first == "compatible_prints" || opt.first == "compatible_printers") {
if (m_colored_Label != nullptr) { wxStaticText* label = (m_colored_Labels.find(opt.first) == m_colored_Labels.end()) ? nullptr : m_colored_Labels.at(opt.first);
m_colored_Label->SetForegroundColour(*color); if (label) {
m_colored_Label->Refresh(true); label->SetForegroundColour(*color);
label->Refresh(true);
} }
continue; continue;
} }
@ -449,9 +450,10 @@ void Tab::update_changed_ui()
tt = &m_tt_white_bullet; tt = &m_tt_white_bullet;
} }
if (opt.first == "bed_shape" || opt.first == "compatible_prints" || opt.first == "compatible_printers") { if (opt.first == "bed_shape" || opt.first == "compatible_prints" || opt.first == "compatible_printers") {
if (m_colored_Label != nullptr) { wxStaticText* label = (m_colored_Labels.find(opt.first) == m_colored_Labels.end()) ? nullptr : m_colored_Labels.at(opt.first);
m_colored_Label->SetForegroundColour(*color); if (label) {
m_colored_Label->Refresh(true); label->SetForegroundColour(*color);
label->Refresh(true);
} }
continue; continue;
} }
@ -668,7 +670,8 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/)
} }
if (group->title == _("Profile dependencies")) { if (group->title == _("Profile dependencies")) {
if (m_type != Slic3r::Preset::TYPE_PRINTER && (m_options_list["compatible_printers"] & os) == 0) { // "compatible_printers" option doesn't exists in Printer Settimgs Tab
if (m_type != Preset::TYPE_PRINTER && (m_options_list["compatible_printers"] & os) == 0) {
to_sys ? group->back_to_sys_value("compatible_printers") : group->back_to_initial_value("compatible_printers"); to_sys ? group->back_to_sys_value("compatible_printers") : group->back_to_initial_value("compatible_printers");
load_key_value("compatible_printers", true/*some value*/, true); load_key_value("compatible_printers", true/*some value*/, true);
@ -676,7 +679,8 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/)
m_compatible_printers.checkbox->SetValue(is_empty); m_compatible_printers.checkbox->SetValue(is_empty);
is_empty ? m_compatible_printers.btn->Disable() : m_compatible_printers.btn->Enable(); is_empty ? m_compatible_printers.btn->Disable() : m_compatible_printers.btn->Enable();
} }
if ((m_type == Slic3r::Preset::TYPE_PRINT || m_type == Slic3r::Preset::TYPE_SLA_PRINT) && (m_options_list["compatible_prints"] & os) == 0) { // "compatible_prints" option exists only in Filament Settimgs and Materials Tabs
if ((m_type == Preset::TYPE_FILAMENT || m_type == Preset::TYPE_SLA_MATERIAL) && (m_options_list["compatible_prints"] & os) == 0) {
to_sys ? group->back_to_sys_value("compatible_prints") : group->back_to_initial_value("compatible_prints"); to_sys ? group->back_to_sys_value("compatible_prints") : group->back_to_initial_value("compatible_prints");
load_key_value("compatible_prints", true/*some value*/, true); load_key_value("compatible_prints", true/*some value*/, true);
@ -754,10 +758,17 @@ void Tab::update_visibility()
{ {
Freeze(); // There is needed Freeze/Thaw to avoid a flashing after Show/Layout Freeze(); // There is needed Freeze/Thaw to avoid a flashing after Show/Layout
// m_detach_preset_btn will be shown always after call page->update_visibility()
// So let save a "show state" of m_detach_preset_btn before update_visibility
bool was_shown = m_detach_preset_btn->IsShown();
for (auto page : m_pages) for (auto page : m_pages)
page->update_visibility(m_mode); page->update_visibility(m_mode);
update_page_tree_visibility(); update_page_tree_visibility();
// update visibility for detach_preset_btn
m_detach_preset_btn->Show(was_shown);
Layout(); Layout();
Thaw(); Thaw();
} }
@ -942,6 +953,52 @@ void Tab::on_presets_changed()
m_dependent_tabs.clear(); m_dependent_tabs.clear();
} }
void Tab::build_preset_description_line(ConfigOptionsGroup* optgroup)
{
auto description_line = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
auto detach_preset_btn = [this](wxWindow* parent) {
add_scaled_button(parent, &m_detach_preset_btn, "lock_open_sys", _(L("Detach from system preset")), wxBU_LEFT | wxBU_EXACTFIT);
ScalableButton* btn = m_detach_preset_btn;
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
btn->Bind(wxEVT_BUTTON, [this, parent](wxCommandEvent&)
{
bool system = m_presets->get_edited_preset().is_system;
bool dirty = m_presets->get_edited_preset().is_dirty;
wxString msg_text = system ?
_(L("A copy of the current system preset will be created, which will be detached from the system preset.")) :
_(L("The current custom preset will be detached from the parent system preset."));
if (dirty) {
msg_text += "\n\n";
msg_text += _(L("Modifications to the current profile will be saved."));
}
msg_text += "\n\n";
msg_text += _(L("This action is not revertable.\nDo you want to proceed?"));
wxMessageDialog dialog(parent, msg_text, _(L("Detach preset")), wxICON_WARNING | wxYES_NO | wxCANCEL);
if (dialog.ShowModal() == wxID_YES)
save_preset(m_presets->get_edited_preset().is_system ? std::string() : m_presets->get_edited_preset().name, true);
});
btn->Hide();
return sizer;
};
Line line = Line{ "", "" };
line.full_width = 1;
line.append_widget(description_line);
line.append_widget(detach_preset_btn);
optgroup->append_line(line);
}
void Tab::update_preset_description_line() void Tab::update_preset_description_line()
{ {
const Preset* parent = m_presets->get_selected_preset_parent(); const Preset* parent = m_presets->get_selected_preset_parent();
@ -1007,14 +1064,18 @@ void Tab::update_preset_description_line()
default: break; default: break;
} }
} }
else else if (!preset.alias.empty())
{ {
description_line += "\n\n\t" + _(L("full profile name")) + ": \n\t\t" + parent->name; description_line += "\n\n\t" + _(L("full profile name")) + ": \n\t\t" + preset.name;
description_line += "\n\t" + _(L("symbolic profile name")) + ": \n\t\t" + parent->alias; description_line += "\n\t" + _(L("symbolic profile name")) + ": \n\t\t" + preset.alias;
} }
} }
m_parent_preset_description_line->SetText(description_line, false); m_parent_preset_description_line->SetText(description_line, false);
if (m_detach_preset_btn)
m_detach_preset_btn->Show(parent && parent->is_system && !preset.is_default);
Layout();
} }
void Tab::update_frequently_changed_parameters() void Tab::update_frequently_changed_parameters()
@ -1256,21 +1317,16 @@ void TabPrint::build()
page = add_options_page(_(L("Dependencies")), "wrench.png"); page = add_options_page(_(L("Dependencies")), "wrench.png");
optgroup = page->new_optgroup(_(L("Profile dependencies"))); optgroup = page->new_optgroup(_(L("Profile dependencies")));
line = optgroup->create_single_option_line("compatible_printers");
line.widget = [this](wxWindow* parent) { create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_printers); return compatible_widget_create(parent, m_compatible_printers);
}; });
optgroup->append_line(line, &m_colored_Label);
option = optgroup->get_option("compatible_printers_condition"); option = optgroup->get_option("compatible_printers_condition");
option.opt.full_width = true; option.opt.full_width = true;
optgroup->append_single_option_line(option); optgroup->append_single_option_line(option);
line = Line{ "", "" }; build_preset_description_line(optgroup.get());
line.full_width = 1;
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
optgroup->append_line(line);
} }
// Reload current config (aka presets->edited_preset->config) into the UI fields. // Reload current config (aka presets->edited_preset->config) into the UI fields.
@ -1546,31 +1602,23 @@ void TabFilament::build()
page = add_options_page(_(L("Dependencies")), "wrench.png"); page = add_options_page(_(L("Dependencies")), "wrench.png");
optgroup = page->new_optgroup(_(L("Profile dependencies"))); optgroup = page->new_optgroup(_(L("Profile dependencies")));
create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) {
line = optgroup->create_single_option_line("compatible_printers");
line.widget = [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_printers); return compatible_widget_create(parent, m_compatible_printers);
}; });
optgroup->append_line(line, &m_colored_Label);
option = optgroup->get_option("compatible_printers_condition"); option = optgroup->get_option("compatible_printers_condition");
option.opt.full_width = true; option.opt.full_width = true;
optgroup->append_single_option_line(option); optgroup->append_single_option_line(option);
line = optgroup->create_single_option_line("compatible_prints"); create_line_with_widget(optgroup.get(), "compatible_prints", [this](wxWindow* parent) {
line.widget = [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_prints); return compatible_widget_create(parent, m_compatible_prints);
}; });
optgroup->append_line(line, &m_colored_Label);
option = optgroup->get_option("compatible_prints_condition"); option = optgroup->get_option("compatible_prints_condition");
option.opt.full_width = true; option.opt.full_width = true;
optgroup->append_single_option_line(option); optgroup->append_single_option_line(option);
line = Line{ "", "" }; build_preset_description_line(optgroup.get());
line.full_width = 1;
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
optgroup->append_line(line);
} }
// Reload current config (aka presets->edited_preset->config) into the UI fields. // Reload current config (aka presets->edited_preset->config) into the UI fields.
@ -1798,38 +1846,10 @@ void TabPrinter::build_fff()
auto page = add_options_page(_(L("General")), "printer"); auto page = add_options_page(_(L("General")), "printer");
auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); auto optgroup = page->new_optgroup(_(L("Size and coordinates")));
Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" }; create_line_with_widget(optgroup.get(), "bed_shape", [this](wxWindow* parent) {
line.widget = [this](wxWindow* parent) { return create_bed_shape_widget(parent);
ScalableButton* btn; });
add_scaled_button(parent, &btn, "printer_white", " " + _(L("Set")) + " " + dots, wxBU_LEFT | wxBU_EXACTFIT);
btn->SetFont(wxGetApp().normal_font());
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
{
BedShapeDialog dlg(this);
dlg.build_dialog(*m_config->option<ConfigOptionPoints>("bed_shape"),
*m_config->option<ConfigOptionString>("bed_custom_texture"),
*m_config->option<ConfigOptionString>("bed_custom_model"));
if (dlg.ShowModal() == wxID_OK) {
const std::vector<Vec2d>& shape = dlg.get_shape();
const std::string& custom_texture = dlg.get_custom_texture();
const std::string& custom_model = dlg.get_custom_model();
if (!shape.empty())
{
load_key_value("bed_shape", shape);
load_key_value("bed_custom_texture", custom_texture);
load_key_value("bed_custom_model", custom_model);
update_changed_ui();
}
}
}));
return sizer;
};
optgroup->append_line(line, &m_colored_Label);
optgroup->append_single_option_line("max_print_height"); optgroup->append_single_option_line("max_print_height");
optgroup->append_single_option_line("z_offset"); optgroup->append_single_option_line("z_offset");
@ -2020,12 +2040,8 @@ void TabPrinter::build_fff()
page = add_options_page(_(L("Dependencies")), "wrench.png"); page = add_options_page(_(L("Dependencies")), "wrench.png");
optgroup = page->new_optgroup(_(L("Profile dependencies"))); optgroup = page->new_optgroup(_(L("Profile dependencies")));
line = Line{ "", "" };
line.full_width = 1; build_preset_description_line(optgroup.get());
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
optgroup->append_line(line);
build_unregular_pages(); build_unregular_pages();
@ -2042,39 +2058,9 @@ void TabPrinter::build_sla()
auto page = add_options_page(_(L("General")), "printer"); auto page = add_options_page(_(L("General")), "printer");
auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); auto optgroup = page->new_optgroup(_(L("Size and coordinates")));
Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" }; create_line_with_widget(optgroup.get(), "bed_shape", [this](wxWindow* parent) {
line.widget = [this](wxWindow* parent) { return create_bed_shape_widget(parent);
ScalableButton* btn; });
add_scaled_button(parent, &btn, "printer_white", " " + _(L("Set")) + " " + dots, wxBU_LEFT | wxBU_EXACTFIT);
btn->SetFont(wxGetApp().normal_font());
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
{
BedShapeDialog dlg(this);
dlg.build_dialog(*m_config->option<ConfigOptionPoints>("bed_shape"),
*m_config->option<ConfigOptionString>("bed_custom_texture"),
*m_config->option<ConfigOptionString>("bed_custom_model"));
if (dlg.ShowModal() == wxID_OK) {
const std::vector<Vec2d>& shape = dlg.get_shape();
const std::string& custom_texture = dlg.get_custom_texture();
const std::string& custom_model = dlg.get_custom_model();
if (!shape.empty())
{
load_key_value("bed_shape", shape);
load_key_value("bed_custom_texture", custom_texture);
load_key_value("bed_custom_model", custom_model);
update_changed_ui();
}
}
}));
return sizer;
};
optgroup->append_line(line, &m_colored_Label);
optgroup->append_single_option_line("max_print_height"); optgroup->append_single_option_line("max_print_height");
optgroup = page->new_optgroup(_(L("Display"))); optgroup = page->new_optgroup(_(L("Display")));
@ -2082,7 +2068,7 @@ void TabPrinter::build_sla()
optgroup->append_single_option_line("display_height"); optgroup->append_single_option_line("display_height");
auto option = optgroup->get_option("display_pixels_x"); auto option = optgroup->get_option("display_pixels_x");
line = { _(option.opt.full_label), "" }; Line line = { _(option.opt.full_label), "" };
line.append_option(option); line.append_option(option);
line.append_option(optgroup->get_option("display_pixels_y")); line.append_option(optgroup->get_option("display_pixels_y"));
optgroup->append_line(line); optgroup->append_line(line);
@ -2136,12 +2122,8 @@ void TabPrinter::build_sla()
page = add_options_page(_(L("Dependencies")), "wrench.png"); page = add_options_page(_(L("Dependencies")), "wrench.png");
optgroup = page->new_optgroup(_(L("Profile dependencies"))); optgroup = page->new_optgroup(_(L("Profile dependencies")));
line = Line{ "", "" };
line.full_width = 1; build_preset_description_line(optgroup.get());
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
optgroup->append_line(line);
} }
void TabPrinter::update_serial_ports() void TabPrinter::update_serial_ports()
@ -2604,6 +2586,15 @@ void TabPrinter::update_fff()
void TabPrinter::update_sla() void TabPrinter::update_sla()
{ ; } { ; }
void Tab::update_ui_items_related_on_parent_preset(const Preset* selected_preset_parent)
{
m_is_default_preset = selected_preset_parent != nullptr && selected_preset_parent->is_default;
m_bmp_non_system = selected_preset_parent ? &m_bmp_value_unlock : &m_bmp_white_bullet;
m_ttg_non_system = selected_preset_parent ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns;
m_tt_non_system = selected_preset_parent ? &m_tt_value_unlock : &m_ttg_white_bullet_ns;
}
// Initialize the UI from the current preset // Initialize the UI from the current preset
void Tab::load_current_preset() void Tab::load_current_preset()
{ {
@ -2622,12 +2613,7 @@ void Tab::load_current_preset()
// Reload preset pages with the new configuration values. // Reload preset pages with the new configuration values.
reload_config(); reload_config();
const Preset* selected_preset_parent = m_presets->get_selected_preset_parent(); update_ui_items_related_on_parent_preset(m_presets->get_selected_preset_parent());
m_is_default_preset = selected_preset_parent != nullptr && selected_preset_parent->is_default;
m_bmp_non_system = selected_preset_parent ? &m_bmp_value_unlock : &m_bmp_white_bullet;
m_ttg_non_system = selected_preset_parent ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns;
m_tt_non_system = selected_preset_parent ? &m_tt_value_unlock : &m_ttg_white_bullet_ns;
// m_undo_to_sys_btn->Enable(!preset.is_default); // m_undo_to_sys_btn->Enable(!preset.is_default);
@ -2779,7 +2765,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
bool printer_tab = m_presets->type() == Preset::TYPE_PRINTER; bool printer_tab = m_presets->type() == Preset::TYPE_PRINTER;
bool canceled = false; bool canceled = false;
bool technology_changed = false; bool technology_changed = false;
m_dependent_tabs = {}; m_dependent_tabs.clear();
if (current_dirty && ! may_discard_current_dirty_preset()) { if (current_dirty && ! may_discard_current_dirty_preset()) {
canceled = true; canceled = true;
} else if (print_tab) { } else if (print_tab) {
@ -2875,10 +2861,10 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
// Mark the print & filament enabled if they are compatible with the currently selected preset. // Mark the print & filament enabled if they are compatible with the currently selected preset.
// The following method should not discard changes of current print or filament presets on change of a printer profile, // The following method should not discard changes of current print or filament presets on change of a printer profile,
// if they are compatible with the current printer. // if they are compatible with the current printer.
auto update_compatible_type = [](bool technology_changed, bool on_page, bool show_incompatible_presets) { auto update_compatible_type = [delete_current](bool technology_changed, bool on_page, bool show_incompatible_presets) {
return technology_changed ? PresetSelectCompatibleType::Always : return (delete_current || technology_changed) ? PresetSelectCompatibleType::Always :
on_page ? PresetSelectCompatibleType::Never : on_page ? PresetSelectCompatibleType::Never :
(show_incompatible_presets ? PresetSelectCompatibleType::OnlyIfWasCompatible : PresetSelectCompatibleType::Always); show_incompatible_presets ? PresetSelectCompatibleType::OnlyIfWasCompatible : PresetSelectCompatibleType::Always;
}; };
if (current_dirty || delete_current || print_tab || printer_tab) if (current_dirty || delete_current || print_tab || printer_tab)
m_preset_bundle->update_compatible( m_preset_bundle->update_compatible(
@ -3033,18 +3019,20 @@ void Tab::OnKeyDown(wxKeyEvent& event)
// and activates the new preset. // and activates the new preset.
// Wizard calls save_preset with a name "My Settings", otherwise no name is provided and this method // Wizard calls save_preset with a name "My Settings", otherwise no name is provided and this method
// opens a Slic3r::GUI::SavePresetWindow dialog. // opens a Slic3r::GUI::SavePresetWindow dialog.
void Tab::save_preset(std::string name /*= ""*/) void Tab::save_preset(std::string name /*= ""*/, bool detach)
{ {
// since buttons(and choices too) don't get focus on Mac, we set focus manually // since buttons(and choices too) don't get focus on Mac, we set focus manually
// to the treectrl so that the EVT_* events are fired for the input field having // to the treectrl so that the EVT_* events are fired for the input field having
// focus currently.is there anything better than this ? // focus currently.is there anything better than this ?
//! m_treectrl->OnSetFocus(); //! m_treectrl->OnSetFocus();
std::string suffix = detach ? _utf8(L("Detached")) : _CTX_utf8(L_CONTEXT("Copy", "PresetName"), "PresetName");
if (name.empty()) { if (name.empty()) {
const Preset &preset = m_presets->get_selected_preset(); const Preset &preset = m_presets->get_selected_preset();
auto default_name = preset.is_default ? "Untitled" : auto default_name = preset.is_default ? "Untitled" :
// preset.is_system ? (boost::format(_utf8(L("%1% - Copy"))) % preset.name).str() : // preset.is_system ? (boost::format(_CTX_utf8(L_CONTEXT("%1% - Copy", "PresetName"), "PresetName")) % preset.name).str() :
preset.is_system ? (boost::format(_CTX_utf8(L_CONTEXT("%1% - Copy", "PresetName"), "PresetName")) % preset.name).str() : preset.is_system ? (boost::format(("%1% - %2%")) % preset.name % suffix).str() :
preset.name; preset.name;
bool have_extention = boost::iends_with(default_name, ".ini"); bool have_extention = boost::iends_with(default_name, ".ini");
@ -3094,8 +3082,9 @@ void Tab::save_preset(std::string name /*= ""*/)
} }
// Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini // Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
m_presets->save_current_preset(name); m_presets->save_current_preset(name, detach);
// Mark the print & filament enabled if they are compatible with the currently selected preset. // Mark the print & filament enabled if they are compatible with the currently selected preset.
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never); m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
// Add the new item into the UI component, remove dirty flags and activate the saved item. // Add the new item into the UI component, remove dirty flags and activate the saved item.
update_tab_ui(); update_tab_ui();
@ -3106,6 +3095,11 @@ void Tab::save_preset(std::string name /*= ""*/)
if (m_type == Preset::TYPE_PRINTER) if (m_type == Preset::TYPE_PRINTER)
static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count; static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count;
// Parent preset is "default" after detaching, so we should to update UI values, related on parent preset
if (detach)
update_ui_items_related_on_parent_preset(m_presets->get_selected_preset_parent());
update_changed_ui(); update_changed_ui();
/* If filament preset is saved for multi-material printer preset, /* If filament preset is saved for multi-material printer preset,
@ -3113,6 +3107,30 @@ void Tab::save_preset(std::string name /*= ""*/)
* but in full_config a filament_colors option aren't.*/ * but in full_config a filament_colors option aren't.*/
if (m_type == Preset::TYPE_FILAMENT && wxGetApp().extruders_edited_cnt() > 1) if (m_type == Preset::TYPE_FILAMENT && wxGetApp().extruders_edited_cnt() > 1)
wxGetApp().plater()->force_filament_colors_update(); wxGetApp().plater()->force_filament_colors_update();
{
// Profile compatiblity is updated first when the profile is saved.
// Update profile selection combo boxes at the depending tabs to reflect modifications in profile compatibility.
std::vector<Preset::Type> dependent;
switch (m_type) {
case Preset::TYPE_PRINT:
dependent = { Preset::TYPE_FILAMENT };
break;
case Preset::TYPE_SLA_PRINT:
dependent = { Preset::TYPE_SLA_MATERIAL };
break;
case Preset::TYPE_PRINTER:
if (static_cast<const TabPrinter*>(this)->m_printer_technology == ptFFF)
dependent = { Preset::TYPE_PRINT, Preset::TYPE_FILAMENT };
else
dependent = { Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL };
break;
default:
break;
}
for (Preset::Type preset_type : dependent)
wxGetApp().get_tab(preset_type)->update_tab_ui();
}
} }
// Called for a currently selected preset. // Called for a currently selected preset.
@ -3170,6 +3188,15 @@ void Tab::update_ui_from_settings()
} }
} }
void Tab::create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, widget_t widget)
{
Line line = optgroup->create_single_option_line(opt_key);
line.widget = widget;
m_colored_Labels[opt_key] = nullptr;
optgroup->append_line(line, &m_colored_Labels[opt_key]);
}
// Return a callback to create a Tab widget to mark the preferences as compatible / incompatible to the current printer. // Return a callback to create a Tab widget to mark the preferences as compatible / incompatible to the current printer.
wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &deps) wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &deps)
{ {
@ -3241,6 +3268,39 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep
return sizer; return sizer;
} }
// Return a callback to create a TabPrinter widget to edit bed shape
wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent)
{
ScalableButton* btn;
add_scaled_button(parent, &btn, "printer_white", " " + _(L("Set")) + " " + dots, wxBU_LEFT | wxBU_EXACTFIT);
btn->SetFont(wxGetApp().normal_font());
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
{
BedShapeDialog dlg(this);
dlg.build_dialog(*m_config->option<ConfigOptionPoints>("bed_shape"),
*m_config->option<ConfigOptionString>("bed_custom_texture"),
*m_config->option<ConfigOptionString>("bed_custom_model"));
if (dlg.ShowModal() == wxID_OK) {
const std::vector<Vec2d>& shape = dlg.get_shape();
const std::string& custom_texture = dlg.get_custom_texture();
const std::string& custom_model = dlg.get_custom_model();
if (!shape.empty())
{
load_key_value("bed_shape", shape);
load_key_value("bed_custom_texture", custom_texture);
load_key_value("bed_custom_model", custom_model);
update_changed_ui();
}
}
}));
return sizer;
}
void Tab::compatible_widget_reload(PresetDependencies &deps) void Tab::compatible_widget_reload(PresetDependencies &deps)
{ {
bool has_any = ! m_config->option<ConfigOptionStrings>(deps.key_list)->values.empty(); bool has_any = ! m_config->option<ConfigOptionStrings>(deps.key_list)->values.empty();
@ -3416,7 +3476,7 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la
void SavePresetWindow::build(const wxString& title, const std::string& default_name, std::vector<std::string> &values) void SavePresetWindow::build(const wxString& title, const std::string& default_name, std::vector<std::string> &values)
{ {
// TRN Preset // TRN Preset
auto text = new wxStaticText(this, wxID_ANY, from_u8((boost::format(_utf8(L("Save %s as:"))) % title).str()), auto text = new wxStaticText(this, wxID_ANY, from_u8((boost::format(_utf8(L("Save %s as:"))) % into_u8(title)).str()),
wxDefaultPosition, wxDefaultSize); wxDefaultPosition, wxDefaultSize);
m_combo = new wxComboBox(this, wxID_ANY, from_u8(default_name), m_combo = new wxComboBox(this, wxID_ANY, from_u8(default_name),
wxDefaultPosition, wxDefaultSize, 0, 0, wxTE_PROCESS_ENTER); wxDefaultPosition, wxDefaultSize, 0, 0, wxTE_PROCESS_ENTER);
@ -3544,30 +3604,24 @@ void TabSLAMaterial::build()
page = add_options_page(_(L("Dependencies")), "wrench.png"); page = add_options_page(_(L("Dependencies")), "wrench.png");
optgroup = page->new_optgroup(_(L("Profile dependencies"))); optgroup = page->new_optgroup(_(L("Profile dependencies")));
Line line = optgroup->create_single_option_line("compatible_printers");
line.widget = [this](wxWindow* parent) { create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_printers); return compatible_widget_create(parent, m_compatible_printers);
}; });
optgroup->append_line(line, &m_colored_Label);
option = optgroup->get_option("compatible_printers_condition"); option = optgroup->get_option("compatible_printers_condition");
option.opt.full_width = true; option.opt.full_width = true;
optgroup->append_single_option_line(option); optgroup->append_single_option_line(option);
line = optgroup->create_single_option_line("compatible_prints"); create_line_with_widget(optgroup.get(), "compatible_prints", [this](wxWindow* parent) {
line.widget = [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_prints); return compatible_widget_create(parent, m_compatible_prints);
}; });
optgroup->append_line(line, &m_colored_Label);
option = optgroup->get_option("compatible_prints_condition"); option = optgroup->get_option("compatible_prints_condition");
option.opt.full_width = true; option.opt.full_width = true;
optgroup->append_single_option_line(option); optgroup->append_single_option_line(option);
line = Line{ "", "" }; build_preset_description_line(optgroup.get());
line.full_width = 1;
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
optgroup->append_line(line);
} }
// Reload current config (aka presets->edited_preset->config) into the UI fields. // Reload current config (aka presets->edited_preset->config) into the UI fields.
@ -3674,22 +3728,16 @@ void TabSLAPrint::build()
page = add_options_page(_(L("Dependencies")), "wrench"); page = add_options_page(_(L("Dependencies")), "wrench");
optgroup = page->new_optgroup(_(L("Profile dependencies"))); optgroup = page->new_optgroup(_(L("Profile dependencies")));
Line line = optgroup->create_single_option_line("compatible_printers");//Line { _(L("Compatible printers")), "" };
line.widget = [this](wxWindow* parent) { create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_printers); return compatible_widget_create(parent, m_compatible_printers);
}; });
optgroup->append_line(line, &m_colored_Label);
option = optgroup->get_option("compatible_printers_condition"); option = optgroup->get_option("compatible_printers_condition");
option.opt.full_width = true; option.opt.full_width = true;
optgroup->append_single_option_line(option); optgroup->append_single_option_line(option);
line = Line{ "", "" }; build_preset_description_line(optgroup.get());
line.full_width = 1;
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
optgroup->append_line(line);
} }
// Reload current config (aka presets->edited_preset->config) into the UI fields. // Reload current config (aka presets->edited_preset->config) into the UI fields.

View file

@ -201,7 +201,7 @@ protected:
bool m_disable_tree_sel_changed_event; bool m_disable_tree_sel_changed_event;
bool m_show_incompatible_presets; bool m_show_incompatible_presets;
std::vector<Preset::Type> m_dependent_tabs = {}; std::vector<Preset::Type> m_dependent_tabs;
enum OptStatus { osSystemValue = 1, osInitValue = 2 }; enum OptStatus { osSystemValue = 1, osInitValue = 2 };
std::map<std::string, int> m_options_list; std::map<std::string, int> m_options_list;
int m_opt_status_value = 0; int m_opt_status_value = 0;
@ -227,7 +227,12 @@ public:
PresetCollection* m_presets; PresetCollection* m_presets;
DynamicPrintConfig* m_config; DynamicPrintConfig* m_config;
ogStaticText* m_parent_preset_description_line; ogStaticText* m_parent_preset_description_line;
wxStaticText* m_colored_Label = nullptr; ScalableButton* m_detach_preset_btn = nullptr;
// map of option name -> wxStaticText (colored label, associated with option)
// Used for options which don't have corresponded field
std::map<std::string, wxStaticText*> m_colored_Labels;
// Counter for the updating (because of an update() function can have a recursive behavior): // Counter for the updating (because of an update() function can have a recursive behavior):
// 1. increase value from the very beginning of an update() function // 1. increase value from the very beginning of an update() function
// 2. decrease value at the end of an update() function // 2. decrease value at the end of an update() function
@ -253,6 +258,7 @@ public:
const wxString& label = wxEmptyString, const wxString& label = wxEmptyString,
long style = wxBU_EXACTFIT | wxNO_BORDER); long style = wxBU_EXACTFIT | wxNO_BORDER);
void add_scaled_bitmap(wxWindow* parent, ScalableBitmap& btn, const std::string& icon_name); void add_scaled_bitmap(wxWindow* parent, ScalableBitmap& btn, const std::string& icon_name);
void update_ui_items_related_on_parent_preset(const Preset* selected_preset_parent);
void load_current_preset(); void load_current_preset();
void rebuild_page_tree(); void rebuild_page_tree();
void update_page_tree_visibility(); void update_page_tree_visibility();
@ -264,7 +270,7 @@ public:
void OnTreeSelChange(wxTreeEvent& event); void OnTreeSelChange(wxTreeEvent& event);
void OnKeyDown(wxKeyEvent& event); void OnKeyDown(wxKeyEvent& event);
void save_preset(std::string name = ""); void save_preset(std::string name = std::string(), bool detach = false);
void delete_preset(); void delete_preset();
void toggle_show_hide_incompatible(); void toggle_show_hide_incompatible();
void update_show_hide_incompatible_button(); void update_show_hide_incompatible_button();
@ -306,11 +312,13 @@ public:
void update_wiping_button_visibility(); void update_wiping_button_visibility();
protected: protected:
void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, widget_t widget);
wxSizer* compatible_widget_create(wxWindow* parent, PresetDependencies &deps); wxSizer* compatible_widget_create(wxWindow* parent, PresetDependencies &deps);
void compatible_widget_reload(PresetDependencies &deps); void compatible_widget_reload(PresetDependencies &deps);
void load_key_value(const std::string& opt_key, const boost::any& value, bool saved_value = false); void load_key_value(const std::string& opt_key, const boost::any& value, bool saved_value = false);
void on_presets_changed(); void on_presets_changed();
void build_preset_description_line(ConfigOptionsGroup* optgroup);
void update_preset_description_line(); void update_preset_description_line();
void update_frequently_changed_parameters(); void update_frequently_changed_parameters();
void fill_icon_descriptions(); void fill_icon_descriptions();
@ -406,6 +414,8 @@ public:
void init_options_list() override; void init_options_list() override;
void msw_rescale() override; void msw_rescale() override;
bool supports_printer_technology(const PrinterTechnology /* tech */) override { return true; } bool supports_printer_technology(const PrinterTechnology /* tech */) override { return true; }
wxSizer* create_bed_shape_widget(wxWindow* parent);
}; };
class TabSLAMaterial : public Tab class TabSLAMaterial : public Tab

View file

@ -29,7 +29,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
add_subdirectory(libnest2d) add_subdirectory(libnest2d)
add_subdirectory(libslic3r) add_subdirectory(libslic3r)
add_subdirectory(timeutils) add_subdirectory(slic3rutils)
add_subdirectory(fff_print) add_subdirectory(fff_print)
add_subdirectory(sla_print) add_subdirectory(sla_print)
add_subdirectory(cpp17 EXCLUDE_FROM_ALL) # does not have to be built all the time add_subdirectory(cpp17 EXCLUDE_FROM_ALL) # does not have to be built all the time

View file

@ -13,6 +13,7 @@ add_executable(${_TEST_NAME}_tests
test_stl.cpp test_stl.cpp
test_meshsimplify.cpp test_meshsimplify.cpp
test_meshboolean.cpp test_meshboolean.cpp
test_timeutils.cpp
) )
if (TARGET OpenVDB::openvdb) if (TARGET OpenVDB::openvdb)

View file

@ -1,4 +1,4 @@
#include <catch_main.hpp> #include <catch2/catch.hpp>
#include "libslic3r/Time.hpp" #include "libslic3r/Time.hpp"
@ -6,9 +6,9 @@
#include <iomanip> #include <iomanip>
#include <locale> #include <locale>
namespace { using namespace Slic3r;
void test_time_fmt(Slic3r::Utils::TimeFormat fmt) { static void test_time_fmt(Slic3r::Utils::TimeFormat fmt) {
using namespace Slic3r::Utils; using namespace Slic3r::Utils;
time_t t = get_current_time_utc(); time_t t = get_current_time_utc();
@ -26,7 +26,6 @@ void test_time_fmt(Slic3r::Utils::TimeFormat fmt) {
parsedtime = str2time("not valid string", TimeZone::utc, fmt); parsedtime = str2time("not valid string", TimeZone::utc, fmt);
REQUIRE(parsedtime == time_t(-1)); REQUIRE(parsedtime == time_t(-1));
} }
}
TEST_CASE("ISO8601Z", "[Timeutils]") { TEST_CASE("ISO8601Z", "[Timeutils]") {
test_time_fmt(Slic3r::Utils::TimeFormat::iso8601Z); test_time_fmt(Slic3r::Utils::TimeFormat::iso8601Z);

View file

@ -1,11 +1,10 @@
get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
add_executable(${_TEST_NAME}_tests add_executable(${_TEST_NAME}_tests
${_TEST_NAME}_tests_main.cpp ${_TEST_NAME}_tests_main.cpp
${PROJECT_SOURCE_DIR}/src/libslic3r/Time.cpp
${PROJECT_SOURCE_DIR}/src/libslic3r/Time.hpp
) )
target_link_libraries(${_TEST_NAME}_tests test_common)
target_link_libraries(${_TEST_NAME}_tests test_common libslic3r_gui)
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ")
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${CATCH_EXTRA_ARGS}) add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "${CATCH_EXTRA_ARGS} exclude:[NotWorking]")

View file

@ -0,0 +1,22 @@
#include <catch_main.hpp>
#include "slic3r/Utils/Http.hpp"
TEST_CASE("Http", "[Http][NotWorking]") {
Slic3r::Http g = Slic3r::Http::get("https://github.com/");
unsigned status = 0;
g.on_error([&status](std::string, std::string, unsigned http_status) {
status = http_status;
});
g.on_complete([&status](std::string /* body */, unsigned http_status){
status = http_status;
});
g.perform_sync();
REQUIRE(status == 200);
}

View file

@ -3,7 +3,7 @@
set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_NAME "PrusaSlicer")
set(SLIC3R_APP_KEY "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer")
set(SLIC3R_VERSION "2.2.0-rc") set(SLIC3R_VERSION "2.2.0-rc2")
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
set(SLIC3R_RC_VERSION "2,2,0,0") set(SLIC3R_RC_VERSION "2,2,0,0")
set(SLIC3R_RC_VERSION_DOTS "2.2.0.0") set(SLIC3R_RC_VERSION_DOTS "2.2.0.0")