Compare commits

..

1 Commits

Author SHA1 Message Date
Ian Chua
367047f731 fix: bambu slice hover popup disappears to fast macos 2026-05-22 19:24:06 +08:00
25 changed files with 504 additions and 1123 deletions

View File

@@ -142,7 +142,7 @@ jobs:
flatpak: flatpak:
name: "Flatpak" name: "Flatpak"
container: container:
image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-50 image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-49
options: --privileged options: --privileged
volumes: volumes:
- /usr/local/lib/android:/usr/local/lib/android - /usr/local/lib/android:/usr/local/lib/android

View File

@@ -199,22 +199,22 @@ echo -e "${GREEN}All required dependencies found${NC}"
# Install runtime and SDK if requested # Install runtime and SDK if requested
if [[ "$INSTALL_RUNTIME" == true ]]; then if [[ "$INSTALL_RUNTIME" == true ]]; then
echo -e "${YELLOW}Installing GNOME runtime and SDK...${NC}" echo -e "${YELLOW}Installing GNOME runtime and SDK...${NC}"
flatpak install --user -y flathub org.gnome.Platform//50 flatpak install --user -y flathub org.gnome.Platform//49
flatpak install --user -y flathub org.gnome.Sdk//50 flatpak install --user -y flathub org.gnome.Sdk//49
fi fi
# Check if required runtime is available # Check if required runtime is available
if ! flatpak info --user org.gnome.Platform//50 &> /dev/null; then if ! flatpak info --user org.gnome.Platform//49 &> /dev/null; then
echo -e "${RED}Error: GNOME Platform 50 runtime is not installed.${NC}" echo -e "${RED}Error: GNOME Platform 49 runtime is not installed.${NC}"
echo "Run with -i flag to install it automatically, or install manually:" echo "Run with -i flag to install it automatically, or install manually:"
echo "flatpak install --user flathub org.gnome.Platform//50" echo "flatpak install --user flathub org.gnome.Platform//49"
exit 1 exit 1
fi fi
if ! flatpak info --user org.gnome.Sdk//50 &> /dev/null; then if ! flatpak info --user org.gnome.Sdk//49 &> /dev/null; then
echo -e "${RED}Error: GNOME SDK 50 is not installed.${NC}" echo -e "${RED}Error: GNOME SDK 49 is not installed.${NC}"
echo "Run with -i flag to install it automatically, or install manually:" echo "Run with -i flag to install it automatically, or install manually:"
echo "flatpak install --user flathub org.gnome.Sdk//50" echo "flatpak install --user flathub org.gnome.Sdk//49"
exit 1 exit 1
fi fi

View File

@@ -122,7 +122,7 @@ msgid "On highlighted overhangs only"
msgstr "Nur an hervorgehobenen Überhängen" msgstr "Nur an hervorgehobenen Überhängen"
msgid "Erase all" msgid "Erase all"
msgstr "Alles löschen" msgstr ""
msgid "Highlight overhang areas" msgid "Highlight overhang areas"
msgstr "Bereiche mit Überhang hervorheben" msgstr "Bereiche mit Überhang hervorheben"
@@ -350,10 +350,10 @@ msgid "Fixed step drag"
msgstr "Fester Schritt ziehen" msgstr "Fester Schritt ziehen"
msgid "Context Menu" msgid "Context Menu"
msgstr "Kontextmenü" msgstr ""
msgid "Toggle Auto-Drop" msgid "Toggle Auto-Drop"
msgstr "Automatisches Absenken umschalten" msgstr ""
msgid "Single sided scaling" msgid "Single sided scaling"
msgstr "Einseitige Skalierung" msgstr "Einseitige Skalierung"
@@ -509,10 +509,10 @@ msgid "Multiple"
msgstr "Mehrere" msgstr "Mehrere"
msgid "Count" msgid "Count"
msgstr "Anzahl" msgstr ""
msgid "Gap" msgid "Gap"
msgstr "Spalt" msgstr ""
msgid "Spacing" msgid "Spacing"
msgstr "Abstand" msgstr "Abstand"
@@ -883,7 +883,7 @@ msgid "Advanced"
msgstr "Erweiterte Einstellungen" msgstr "Erweiterte Einstellungen"
msgid "Reset all options except the text and operation" msgid "Reset all options except the text and operation"
msgstr "Alle Optionen außer dem Text und der Operation zurücksetzen" msgstr ""
msgid "" msgid ""
"The text cannot be written using the selected font. Please try choosing a " "The text cannot be written using the selected font. Please try choosing a "
@@ -1805,16 +1805,16 @@ msgid "Info"
msgstr "Info" msgstr "Info"
msgid "Loading printer & filament profiles" msgid "Loading printer & filament profiles"
msgstr "Lade Drucker- und Filamentprofile" msgstr ""
msgid "Creating main window" msgid "Creating main window"
msgstr "Erstelle Hauptfenster" msgstr ""
msgid "Loading current preset" msgid "Loading current preset"
msgstr "Lade aktuelles Preset" msgstr ""
msgid "Showing main window" msgid "Showing main window"
msgstr "Zeige Hauptfenster" msgstr ""
msgid "" msgid ""
"The OrcaSlicer configuration file may be corrupted and cannot be parsed.\n" "The OrcaSlicer configuration file may be corrupted and cannot be parsed.\n"
@@ -1897,12 +1897,9 @@ msgid ""
"Please check your network connectivity\n" "Please check your network connectivity\n"
"(HTTP %u)" "(HTTP %u)"
msgstr "" msgstr ""
"Verbindung zu OrcaCloud fehlgeschlagen.\n"
"Bitte überprüfen Sie Ihre Netzwerkverbindung\n"
"(HTTP %u)"
msgid "Cloud Error" msgid "Cloud Error"
msgstr "Cloud-Fehler" msgstr ""
msgid "Retrieving printer information, please try again later." msgid "Retrieving printer information, please try again later."
msgstr "Empfange Druckerinformationen, bitte später erneut versuchen." msgstr "Empfange Druckerinformationen, bitte später erneut versuchen."
@@ -6103,13 +6100,13 @@ msgid "Export"
msgstr "Exportieren" msgstr "Exportieren"
msgid "Sync Presets" msgid "Sync Presets"
msgstr "Presets synchronisieren" msgstr ""
msgid "Pull and apply the latest presets from OrcaCloud" msgid "Pull and apply the latest presets from OrcaCloud"
msgstr "Die neuesten Presets von OrcaCloud abrufen und anwenden" msgstr ""
msgid "You must be logged in to sync presets from cloud." msgid "You must be logged in to sync presets from cloud."
msgstr "Sie müssen angemeldet sein, um Presets aus der Cloud zu synchronisieren." msgstr ""
msgid "Quit" msgid "Quit"
msgstr "Beenden" msgstr "Beenden"
@@ -6239,7 +6236,7 @@ msgid "Preset Bundle"
msgstr "Vorlagen-Bundle" msgstr "Vorlagen-Bundle"
msgid "Syncing presets from cloud…" msgid "Syncing presets from cloud…"
msgstr "Synchronisiere Presets aus der Cloud…" msgstr ""
msgid "Help" msgid "Help"
msgstr "Hilfe" msgstr "Hilfe"
@@ -8944,25 +8941,25 @@ msgid "If enabled, reverses the direction of zoom with mouse wheel."
msgstr "Wenn aktiviert, wird die Richtung des Zooms mit dem Mausrad umgekehrt." msgstr "Wenn aktiviert, wird die Richtung des Zooms mit dem Mausrad umgekehrt."
msgid "Pan" msgid "Pan"
msgstr "Schwenken" msgstr ""
msgid "Left Mouse Drag" msgid "Left Mouse Drag"
msgstr "Linke Maustaste drücken" msgstr ""
msgid "Set the action that dragging the left mouse button should perform." msgid "Set the action that dragging the left mouse button should perform."
msgstr "Legen Sie die Aktion fest, die das Ziehen der linken Maustaste ausführen soll." msgstr ""
msgid "Middle Mouse Drag" msgid "Middle Mouse Drag"
msgstr "Mittlere Maustaste drücken" msgstr ""
msgid "Set the action that dragging the middle mouse button should perform." msgid "Set the action that dragging the middle mouse button should perform."
msgstr "Legen Sie die Aktion fest, die das Ziehen der mittleren Maustaste ausführen soll." msgstr ""
msgid "Right Mouse Drag" msgid "Right Mouse Drag"
msgstr "Rechte Maustaste drücken" msgstr ""
msgid "Set the action that dragging the right mouse button should perform." msgid "Set the action that dragging the right mouse button should perform."
msgstr "Legen Sie die Aktion fest, die das Ziehen der rechten Maustaste ausführen soll." msgstr ""
msgid "Clear my choice on..." msgid "Clear my choice on..."
msgstr "Meine Auswahl löschen bei ..." msgstr "Meine Auswahl löschen bei ..."
@@ -8989,13 +8986,13 @@ msgstr ""
"der Datei." "der Datei."
msgid "Graphics" msgid "Graphics"
msgstr "Grafik" msgstr ""
msgid "Anti-aliasing" msgid "Anti-aliasing"
msgstr "Kantenglättung" msgstr ""
msgid "MSAA Multiplier" msgid "MSAA Multiplier"
msgstr "MSAA-Multiplikator" msgstr ""
msgid "" msgid ""
"Set the Multi-Sample Anti-Aliasing level.\n" "Set the Multi-Sample Anti-Aliasing level.\n"
@@ -9007,19 +9004,12 @@ msgid ""
"\n" "\n"
"Requires application restart." "Requires application restart."
msgstr "" msgstr ""
"Stellen Sie die Stufe der Multi-Sample-Kantenglättung ein.\n"
"Höhere Werte führen zu glatteren Kanten, aber die Auswirkungen auf die "
"Leistung sind exponentiell.\n"
"Niedrigere Werte verbessern die Leistung auf Kosten von gezackten Kanten.\n"
"Wenn deaktiviert, wird empfohlen, FXAA zu aktivieren, um gezackte Kanten mit minimalen Auswirkungen auf die Leistung zu reduzieren.\n"
"\n"
"Erfordert einen Neustart der Anwendung."
msgid "Disabled" msgid "Disabled"
msgstr "Deaktiviert" msgstr "Deaktiviert"
msgid "FXAA post-processing" msgid "FXAA post-processing"
msgstr "FXAA-Nachbearbeitung" msgstr ""
msgid "" msgid ""
"Applies Fast Approximate Anti-Aliasing as a screen-space pass.\n" "Applies Fast Approximate Anti-Aliasing as a screen-space pass.\n"
@@ -9027,34 +9017,26 @@ msgid ""
"\n" "\n"
"Takes effect immediately." "Takes effect immediately."
msgstr "" msgstr ""
"Führt Fast Approximate Anti-Aliasing als Bildschirmraum-Pass aus.\n"
"Nützlich, um die MSAA-Einstellung zu deaktivieren oder zu reduzieren, um die Leistung zu verbessern.\n"
"\n"
"ist sofort wirksam"
msgid "FPS" msgid "FPS"
msgstr "FPS" msgstr ""
msgid "FPS cap" msgid "FPS cap"
msgstr "FPS-Begrenzung" msgstr ""
msgid "(0 = unlimited)" msgid "(0 = unlimited)"
msgstr "(0 = unbegrenzt)" msgstr ""
msgid "" msgid ""
"Limits viewport frame rate to reduce GPU load and power usage.\n" "Limits viewport frame rate to reduce GPU load and power usage.\n"
"Set to 0 for unlimited frame rate." "Set to 0 for unlimited frame rate."
msgstr "" msgstr ""
"Begrenzt die Bildrate des Viewports, um die GPU-Auslastung und den "
"Energieverbrauch zu reduzieren.\n"
"Auf 0 setzen für unbegrenzte Bildrate."
msgid "Show FPS overlay" msgid "Show FPS overlay"
msgstr "FPS-Overlay anzeigen" msgstr ""
msgid "Displays current viewport FPS in the top-right corner." msgid "Displays current viewport FPS in the top-right corner."
msgstr "Zeigt die aktuelle FPS des Viewports in der oberen rechten Ecke an." msgstr ""
msgid "Login region" msgid "Login region"
msgstr "Login region" msgstr "Login region"
@@ -9225,17 +9207,13 @@ msgid "Skip AMS blacklist check"
msgstr "Überspringen der AMS Blacklist-Prüfung" msgstr "Überspringen der AMS Blacklist-Prüfung"
msgid "(Experimental) Keep painted feature after mesh change" msgid "(Experimental) Keep painted feature after mesh change"
msgstr "(Experimentell) Behalte bemalte Funktionen nach Mesh-Änderung bei" msgstr ""
msgid "" msgid ""
"Attempt to keep painted features (color/seam/support/fuzzy etc.) after " "Attempt to keep painted features (color/seam/support/fuzzy etc.) after "
"changing the object mesh (such as cut/reload from disk/simplify/fix etc.)\n" "changing the object mesh (such as cut/reload from disk/simplify/fix etc.)\n"
"Highly experimental! Slow and may create artifact." "Highly experimental! Slow and may create artifact."
msgstr "" msgstr ""
"Versuchen Sie, bemalte Funktionen (Farbe/Naht/Stütze/unscharf usw.) nach "
"Änderung des Objekt-Meshs (z. B. schneiden/neu laden von der Festplatte/vereinfachen/reparieren usw.) beizubehalten\n"
"Sehr experimentell! Langsam und kann Artefakte erzeugen."
msgid "Allow Abnormal Storage" msgid "Allow Abnormal Storage"
msgstr "Fehlerhaften Speicher zulassen" msgstr "Fehlerhaften Speicher zulassen"
@@ -10961,37 +10939,26 @@ msgid ""
" %s first layer %d %s, other layers %d %s\n" " %s first layer %d %s, other layers %d %s\n"
" %s max delta %d %s, current delta %d %s\n" " %s max delta %d %s, current delta %d %s\n"
msgstr "" msgstr ""
" - %s:\n"
" %s erste Schicht %d %s, andere Schichten %d %s\n"
" %s maximale Delta %d %s, aktuelle Delta %d %s\n"
msgid "" msgid ""
"Some first-layer and other-layer temperature pairs exceed safety limits.\n" "Some first-layer and other-layer temperature pairs exceed safety limits.\n"
msgstr "Einige Temperaturpaare für die erste und andere Schicht überschreiten die Sicherheitsgrenzen.\n" msgstr ""
msgid "" msgid ""
"\n" "\n"
"Invalid pairs:\n" "Invalid pairs:\n"
msgstr "" msgstr ""
"\n"
"Ungültige Paare:\n"
msgid "" msgid ""
"\n" "\n"
"You can go back to edit values, or continue if this is intentional." "You can go back to edit values, or continue if this is intentional."
msgstr "" msgstr ""
"\n"
"Sie können zurückgehen, um die Werte zu bearbeiten, oder fortfahren, wenn dies "
"absichtlich ist."
msgid "" msgid ""
"\n" "\n"
"\n" "\n"
"Continue anyway?" "Continue anyway?"
msgstr "" msgstr ""
"\n"
"\n"
"Trotzdem fortfahren?"
msgid "Temperature Safety Check" msgid "Temperature Safety Check"
msgstr "Temperatur-Sicherheitsprüfung" msgstr "Temperatur-Sicherheitsprüfung"
@@ -11075,10 +11042,6 @@ msgid ""
"\"%1%\"\n" "\"%1%\"\n"
"and \"%2%\" will open without any changes." "and \"%2%\" will open without any changes."
msgstr "" msgstr ""
"Alle \"Neuer Wert\" Einstellungen in\n"
"\"%1%\"\n"
"werden gespeichert und \"%2%\" wird ohne Änderungen geöffnet."
msgid "Click the right mouse button to display the full text." msgid "Click the right mouse button to display the full text."
msgstr "" msgstr ""
@@ -11684,7 +11647,7 @@ msgid "Login"
msgstr "Anmelden" msgstr "Anmelden"
msgid "Login failed. Please try again." msgid "Login failed. Please try again."
msgstr "Anmeldung fehlgeschlagen. Bitte versuchen Sie es erneut." msgstr ""
msgid "[Action Required] " msgid "[Action Required] "
msgstr "[Aktion erforderlich] " msgstr "[Aktion erforderlich] "
@@ -11724,16 +11687,16 @@ msgid "Global shortcuts"
msgstr "Globale Tastaturkürzel" msgstr "Globale Tastaturkürzel"
msgid "Pan View" msgid "Pan View"
msgstr "Ansicht verschieben" msgstr ""
msgid "Rotate View" msgid "Rotate View"
msgstr "Ansicht drehen" msgstr ""
msgid "Middle mouse button" msgid "Middle mouse button"
msgstr "Mittlere Maustaste" msgstr ""
msgid "Zoom View" msgid "Zoom View"
msgstr "Ansicht zoomen" msgstr ""
msgid "" msgid ""
"Auto orients selected objects or all objects. If there are selected objects, " "Auto orients selected objects or all objects. If there are selected objects, "
@@ -12636,8 +12599,6 @@ msgid ""
"The Hollow base pattern is not supported by this support type; Rectilinear " "The Hollow base pattern is not supported by this support type; Rectilinear "
"will be used instead." "will be used instead."
msgstr "" msgstr ""
"Das Hohl-Basis-Muster wird von diesem Stütztyp nicht unterstützt; Stattdessen "
"wird das Rechteckmuster verwendet."
msgid "" msgid ""
"Support enforcers are used but support is not enabled. Please enable support." "Support enforcers are used but support is not enabled. Please enable support."
@@ -14885,16 +14846,16 @@ msgid "Auto For Match"
msgstr "Automatisch für Übereinstimmung" msgstr "Automatisch für Übereinstimmung"
msgid "Enable filament dynamic map" msgid "Enable filament dynamic map"
msgstr "Dynamische Filamentzuordnung aktivieren" msgstr ""
msgid "Enable dynamic filament mapping during print." msgid "Enable dynamic filament mapping during print."
msgstr "Dynamische Filamentzuordnung während des Drucks aktivieren." msgstr ""
msgid "Has filament switcher" msgid "Has filament switcher"
msgstr "Hat Filamentwechsler" msgstr ""
msgid "Printer has a filament switcher hardware (e.g., AMS)." msgid "Printer has a filament switcher hardware (e.g., AMS)."
msgstr "Der Drucker verfügt über eine Filamentwechsler-Hardware (z. B. AMS)." msgstr ""
msgid "Flush temperature" msgid "Flush temperature"
msgstr "Spültemperatur" msgstr "Spültemperatur"
@@ -15415,7 +15376,7 @@ msgstr ""
"unterstützt." "unterstützt."
msgid "Z-buckling bias optimization (experimental)" msgid "Z-buckling bias optimization (experimental)"
msgstr "Z-Buckling-Bias-Optimierung (experimentell)" msgstr ""
msgid "" msgid ""
"Tightens the gyroid wave along the Z (vertical) axis at low infill density " "Tightens the gyroid wave along the Z (vertical) axis at low infill density "
@@ -15424,11 +15385,6 @@ msgid ""
"~30% sparse infill density and above. Only applies when Sparse infill " "~30% sparse infill density and above. Only applies when Sparse infill "
"pattern is set to Gyroid." "pattern is set to Gyroid."
msgstr "" msgstr ""
"Strafft die Gyroid-Welle entlang der Z-Achse (vertikal) bei geringer Fülldichte, "
"um die effektive vertikale Säulenlänge zu verkürzen und die Z-Achsen-Kompressions-"
"Knickfestigkeit zu verbessern. Der Filamentverbrauch bleibt erhalten. Keine "
"Auswirkung bei ~30% einfacher Fülldichte und darüber. Gilt nur, wenn das einfache "
"Füllmuster auf Gyroid eingestellt ist."
msgid "Sparse infill pattern" msgid "Sparse infill pattern"
msgstr "Füllmuster" msgstr "Füllmuster"
@@ -16318,7 +16274,7 @@ msgstr ""
"bringen.Setze den Wert auf 0, um diese Funktion zu deaktivieren." "bringen.Setze den Wert auf 0, um diese Funktion zu deaktivieren."
msgid "Minimum non-zero part cooling fan speed" msgid "Minimum non-zero part cooling fan speed"
msgstr "Minimale nicht-null Lüftergeschwindigkeit für die Teilekühlung" msgstr ""
msgid "" msgid ""
"Some part-cooling fans cannot start spinning when commanded below a certain " "Some part-cooling fans cannot start spinning when commanded below a certain "
@@ -16337,11 +16293,6 @@ msgid ""
"below the one you know it can actually spool at.\n" "below the one you know it can actually spool at.\n"
"Set to 0 to deactivate." "Set to 0 to deactivate."
msgstr "" msgstr ""
"Einige Teilekühlventilatoren können nicht zu drehen beginnen, wenn sie unter einem bestimmten PWM-Arbeitszyklus befehligt werden. Wenn dieser Wert über 0 eingestellt ist, wird jeder nicht-null-Teilekühlventilatorbefehl auf mindestens diesen Prozentsatz angehoben, damit der Lüfter zuverlässig startet. Ein Lüfterbefehl von 0 (Lüfter aus) wird immer genau eingehalten. Diese Begrenzung wird nach jeder anderen Lüfterberechnung angewendet (Erstschicht-Ramp-up, Schichtzeit-Interpolation, Überhangs-/Brücken-/Stützstruktur-Schnittstellen-/Glättungsüberschreibungen), sodass die Skalierung weiterhin im Bereich [dieser Wert, 100%] erfolgt.\n"
"\n"
"Wenn Ihre Firmware den Lüfter bereits unter einem Schwellenwert deaktiviert (z.B. Klipper's [fan] off_below: 0.10 schaltet den Lüfter aus, wenn der befehligte Arbeitszyklus unter 10% liegt), sollten idealerweise dieser Wert und der Firmware-Schwellenwert auf denselben Wert eingestellt werden. Wenn sie übereinstimmen (z.B. off_below: 0.10 in Klipper und 10% hier), garantiert der Slicer, dass er nie einen nicht-null-Wert emittiert, den die Firmware stillschweigend fallen lässt, und der Lüfter nie einen Wert erhält, der unter dem Wert liegt, den er tatsächlich anfahren kann.\n"
"\n"
"Setze den Wert auf 0, um diese Funktion zu deaktivieren."
msgid "%" msgid "%"
msgstr "%" msgstr "%"
@@ -18432,7 +18383,7 @@ msgid "Enable filament ramming"
msgstr "Erlaube Filamentrammen" msgstr "Erlaube Filamentrammen"
msgid "Tool change on wipe tower" msgid "Tool change on wipe tower"
msgstr "Werkzeugwechsel auf dem Reinigungsturm" msgstr ""
msgid "" msgid ""
"Force the toolhead to travel to the wipe tower before issuing the tool " "Force the toolhead to travel to the wipe tower before issuing the tool "
@@ -18443,8 +18394,6 @@ msgid ""
"this option if you want the tool change to always be issued above the wipe " "this option if you want the tool change to always be issued above the wipe "
"tower instead." "tower instead."
msgstr "" msgstr ""
"Erzwinge, dass der Werkzeugkopf zum Reinigungsturm fährt, bevor der Werkzeugwechselbefehl (Tx) ausgegeben wird. Nur relevant für Mehrfach-Extruder (Mehrfach-Werkzeugkopf) Drucker, die einen Typ-2-Reinigungsturm verwenden. Standardmäßig überspringt Orca die Fahrt auf Mehrfach-Werkzeugkopf-Maschinen, da die Firmware den Kopfwechsel übernimmt, was dazu führen kann, dass der Tx-Befehl über dem gedruckten Teil ausgegeben wird. Aktivieren Sie diese Option, wenn Sie möchten, dass der Werkzeugwechsel immer über dem Reinigungsturm ausgegeben wird."
msgid "No sparse layers (beta)" msgid "No sparse layers (beta)"
msgstr "Keine dünnen Schichten (Beta)" msgstr "Keine dünnen Schichten (Beta)"
@@ -19396,7 +19345,7 @@ msgstr ""
"verschiedene Materialien aufeinandertreffen." "verschiedene Materialien aufeinandertreffen."
msgid "Cool down from interface boost during prime tower" msgid "Cool down from interface boost during prime tower"
msgstr "Abkühlung von der Schnittstellen-Boost während des Reinigungsturms" msgstr "^"
msgid "" msgid ""
"When interface-layer temperature boost is active, set the nozzle back to " "When interface-layer temperature boost is active, set the nozzle back to "
@@ -22045,18 +21994,12 @@ msgid ""
"\n" "\n"
"Available nozzle profiles for this printer:" "Available nozzle profiles for this printer:"
msgstr "" msgstr ""
"\n"
"\n"
"Verfügbare Düsenprofile für diesen Drucker:"
msgid "" msgid ""
"\n" "\n"
"\n" "\n"
"Choose YES to switch existing preset:" "Choose YES to switch existing preset:"
msgstr "" msgstr ""
"\n"
"\n"
"Wählen Sie JA, um das vorhandene Profil zu wechseln:"
msgid "Printer Created Successfully" msgid "Printer Created Successfully"
msgstr "Drucker erfolgreich erstellt" msgstr "Drucker erfolgreich erstellt"
@@ -23265,16 +23208,16 @@ msgid "Detection radius"
msgstr "Erkennungsradius" msgstr "Erkennungsradius"
msgid "Selected" msgid "Selected"
msgstr "Ausgewählt" msgstr ""
msgid "Auto-generate" msgid "Auto-generate"
msgstr "Automatisch generieren" msgstr ""
msgid "Generate brim ears using Max angle and Detection radius" msgid "Generate brim ears using Max angle and Detection radius"
msgstr "Mausohren mit Maximalwinkel und Erkennungsradius generieren" msgstr ""
msgid "Add or Select" msgid "Add or Select"
msgstr "Hinzufügen oder auswählen" msgstr ""
msgid "" msgid ""
"Warning: The brim type is not set to \"painted\", the brim ears will not " "Warning: The brim type is not set to \"painted\", the brim ears will not "
@@ -23287,7 +23230,7 @@ msgid "Set the brim type of this object to \"painted\""
msgstr "Den Brim-Typ dieses Objekts auf \"bemalt\" setzen" msgstr "Den Brim-Typ dieses Objekts auf \"bemalt\" setzen"
msgid "invalid brim ears" msgid "invalid brim ears"
msgstr "Ungültige Mausohren" msgstr ""
msgid "Brim Ears" msgid "Brim Ears"
msgstr "Mausohren" msgstr "Mausohren"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
02.00.00.30 02.00.00.29

View File

@@ -22,7 +22,7 @@ ARCH="$(uname -m)"
NO_DEBUG_INFO=false NO_DEBUG_INFO=false
FORCE_PULL=false FORCE_PULL=false
FORCE_CLEAN=true FORCE_CLEAN=true
CONTAINER_IMAGE="ghcr.io/flathub-infra/flatpak-github-actions:gnome-50" CONTAINER_IMAGE="ghcr.io/flathub-infra/flatpak-github-actions:gnome-49"
normalize_arch() { normalize_arch() {
case "$1" in case "$1" in
@@ -142,16 +142,6 @@ fi
DOCKER_RUN_ARGS=(run --rm -i --privileged) DOCKER_RUN_ARGS=(run --rm -i --privileged)
# When building from a git worktree, $PROJECT_ROOT/.git is a file pointing to the
# main repo's git dir (outside $PROJECT_ROOT). The git commands and flatpak-builder
# inside the container need that path to resolve, so bind-mount the common git dir
# read-only at its original absolute path. No-op for a normal clone.
GIT_COMMON_DIR="$(git -C "$PROJECT_ROOT" rev-parse --path-format=absolute --git-common-dir 2>/dev/null || true)"
if [ -n "$GIT_COMMON_DIR" ] && [ "$GIT_COMMON_DIR" != "$PROJECT_ROOT/.git" ]; then
echo " Git worktree detected; mounting common git dir read-only: $GIT_COMMON_DIR"
DOCKER_RUN_ARGS+=(-v "$GIT_COMMON_DIR":"$GIT_COMMON_DIR":ro)
fi
# Pass build parameters as env vars so the inner script doesn't need # Pass build parameters as env vars so the inner script doesn't need
# variable expansion from the outer shell (avoids quoting issues). # variable expansion from the outer shell (avoids quoting issues).
echo "=== Starting Flatpak build inside container ===" echo "=== Starting Flatpak build inside container ==="
@@ -177,16 +167,16 @@ format_duration() {
overall_start=$(date +%s) overall_start=$(date +%s)
install_start=$overall_start install_start=$overall_start
# This container runs as root, but the bind-mounted workspace and .flatpak-builder # The workspace and .flatpak-builder cache are bind-mounted from the host.
# cache are host-user-owned, so git's dubious-ownership check rejects them and # Git inside the container may reject cached source repos as unsafe due to
# breaks flatpak-builder's git checkouts (e.g. wxWidgets). Trust every repo: safe # ownership mismatch, which breaks flatpak-builder when it reuses git sources.
# in this ephemeral build container, and covers the workspace, mirrors and builds. git config --global --add safe.directory /src
git config --global --add safe.directory '*' git config --global --add safe.directory '/src/.flatpak-builder/git/*'
# Install required SDK extensions (not pre-installed in the container image) # Install required SDK extensions (not pre-installed in the container image)
flatpak install -y --noninteractive --arch="$BUILD_ARCH" flathub \ flatpak install -y --noninteractive --arch="$BUILD_ARCH" flathub \
org.gnome.Platform//50 \ org.gnome.Platform//49 \
org.gnome.Sdk//50 \ org.gnome.Sdk//49 \
org.freedesktop.Sdk.Extension.llvm21//25.08 || true org.freedesktop.Sdk.Extension.llvm21//25.08 || true
install_end=$(date +%s) install_end=$(date +%s)

View File

@@ -45,12 +45,6 @@
<color type="primary" scheme_preference="dark">#00695C</color> <color type="primary" scheme_preference="dark">#00695C</color>
</branding> </branding>
<releases> <releases>
<release version="2.4.0-dev" date="2026-05-22" type="development">
<url type="details">https://github.com/OrcaSlicer/OrcaSlicer/releases/tag/nightly-builds</url>
<description>
<p>See the release page for detailed changelog.</p>
</description>
</release>
<release version="2.3.2" date="2025-03-23"> <release version="2.3.2" date="2025-03-23">
<url type="details">https://github.com/OrcaSlicer/OrcaSlicer/releases/tag/v2.3.2</url> <url type="details">https://github.com/OrcaSlicer/OrcaSlicer/releases/tag/v2.3.2</url>
<description> <description>

View File

@@ -1,6 +1,6 @@
app-id: com.orcaslicer.OrcaSlicer app-id: com.orcaslicer.OrcaSlicer
runtime: org.gnome.Platform runtime: org.gnome.Platform
runtime-version: "50" runtime-version: "49"
sdk: org.gnome.Sdk sdk: org.gnome.Sdk
sdk-extensions: sdk-extensions:
- org.freedesktop.Sdk.Extension.llvm21 - org.freedesktop.Sdk.Extension.llvm21
@@ -24,11 +24,6 @@ finish-args:
- --filesystem=xdg-run/gvfs - --filesystem=xdg-run/gvfs
- --filesystem=/run/media - --filesystem=/run/media
- --filesystem=/media - --filesystem=/media
# Network shares (CIFS/NFS) are commonly mounted under /mnt, which the default
# finish-args don't grant; without it, opening a model from such a share fails
# with "The file does not contain any geometry data."
# https://github.com/flathub/com.orcaslicer.OrcaSlicer/issues/2
- --filesystem=/mnt
- --filesystem=/run/spnav.sock:ro - --filesystem=/run/spnav.sock:ro
# Allow read-only access to OrcaSlicer's legacy config and cache directories (if they exist) for migration purposes. # Allow read-only access to OrcaSlicer's legacy config and cache directories (if they exist) for migration purposes.
- --filesystem=~/.var/app/io.github.orcaslicer.OrcaSlicer:ro - --filesystem=~/.var/app/io.github.orcaslicer.OrcaSlicer:ro
@@ -120,12 +115,7 @@ modules:
- -DwxUSE_ZLIB=sys - -DwxUSE_ZLIB=sys
- -DwxUSE_LIBJPEG=sys - -DwxUSE_LIBJPEG=sys
- -DwxUSE_LIBTIFF=OFF - -DwxUSE_LIBTIFF=OFF
# sys, not builtin (unlike the static deps build): wxWidgets installs the
# builtin libwxwebp*.so only for static builds, so a shared build leaves
# them missing at runtime. The GNOME runtime provides libwebp.
- -DwxUSE_LIBWEBP=sys
- -DwxUSE_EXPAT=sys - -DwxUSE_EXPAT=sys
- -DwxUSE_NANOSVG=OFF
- -DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld - -DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld
- -DCMAKE_SHARED_LINKER_FLAGS=-fuse-ld=lld - -DCMAKE_SHARED_LINKER_FLAGS=-fuse-ld=lld
- -DCMAKE_MODULE_LINKER_FLAGS=-fuse-ld=lld - -DCMAKE_MODULE_LINKER_FLAGS=-fuse-ld=lld

View File

@@ -3,7 +3,7 @@
sudo apt update sudo apt update
sudo apt install build-essential flatpak flatpak-builder gnome-software-plugin-flatpak -y sudo apt install build-essential flatpak flatpak-builder gnome-software-plugin-flatpak -y
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install flathub org.gnome.Platform//50 org.gnome.Sdk//50 org.freedesktop.Sdk.Extension.llvm21//25.08 flatpak install flathub org.gnome.Platform//48 org.gnome.Sdk//48
## ##

View File

@@ -23,7 +23,6 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <math.h> #include <math.h>
#include <csignal>
#if defined(__linux__) || defined(__LINUX__) #if defined(__linux__) || defined(__LINUX__)
#include <condition_variable> #include <condition_variable>
@@ -7460,13 +7459,6 @@ extern "C" {
#else /* _MSC_VER */ #else /* _MSC_VER */
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
#ifndef _WIN32
// Ignore SIGPIPE so a write to a closed socket (e.g. a dropped printer
// network connection) returns EPIPE to the caller instead of terminating
// the whole process. Without this, losing the printer link kills
// OrcaSlicer with SIGPIPE (exit 141) and produces no crash report.
std::signal(SIGPIPE, SIG_IGN);
#endif
return CLI().run(argc, argv); return CLI().run(argc, argv);
} }
#endif /* _MSC_VER */ #endif /* _MSC_VER */

View File

@@ -864,10 +864,10 @@ std::string GCodeWriter::_spiral_travel_to_z(double z, const Vec2d &ij_offset, c
// Determine number of segments based on Resolution // Determine number of segments based on Resolution
// -------------------------------------------------------------------- // --------------------------------------------------------------------
const double ref_resolution = 0.01; // reference resolution in mm const double ref_resolution = 0.01; // reference resolution in mm
const double ref_segments = 8.0; // reference number of segments at reference resolution const double ref_segments = 16.0; // reference number of segments at reference resolution
// number of linear segments to use for approximating the arc, clamp between 4 and 16 // number of linear segments to use for approximating the arc, clamp between 4 and 24
const int segments = std::clamp(int(std::round(ref_segments * (ref_resolution / m_resolution))), 4, 16); const int segments = std::clamp(int(std::round(ref_segments * (ref_resolution / m_resolution))), 4, 24);
// -------------------------------------------------------------------- // --------------------------------------------------------------------
const double px = m_pos(0) - m_x_offset; // take plate offset into consideration const double px = m_pos(0) - m_x_offset; // take plate offset into consideration

View File

@@ -581,6 +581,14 @@ void Preset::load_info(const std::string& file)
catch (...) { catch (...) {
return; return;
} }
//TODO: workaround for current info file convert, will remove it later
if (this->updated_time == 0) {
this->updated_time = (long long)Slic3r::Utils::get_current_time_utc();
//this->sync_info = "update";
BOOST_LOG_TRIVIAL(info) << boost::format("old info file, updated time to %1%") % this->updated_time;
save_info();
}
} }
void Preset::save_info(std::string file) void Preset::save_info(std::string file)
@@ -2178,29 +2186,19 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
} }
} }
// base_id is only required for presets inheriting from a parent. Root presets // base_id
// with an empty "inherits" field intentionally have no base_id. if (preset_values.find(BBL_JSON_KEY_BASE_ID) == preset_values.end()) {
std::string based_id; BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find base_id, not loading for user preset %1%") % canonical_name;
const auto base_id = preset_values.find(BBL_JSON_KEY_BASE_ID);
if (base_id != preset_values.end()) {
based_id = base_id->second;
} else {
const auto inherits_iter = preset_values.find(BBL_JSON_KEY_INHERITS);
const bool preset_inherits_from_parent = inherits_iter != preset_values.end() && !inherits_iter->second.empty();
if (preset_inherits_from_parent) {
// This indicates that there is inherits exists but there is no base_id
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__
<< boost::format("can not find base_id, not loading for user preset %1%") % canonical_name;
unlock(); unlock();
return false; return false;
} }
} std::string cloud_base_id = preset_values[BBL_JSON_KEY_BASE_ID];
//filament_id //filament_id
std::string cloud_filament_id; std::string cloud_filament_id;
if ((m_type == Preset::TYPE_FILAMENT) && preset_values.find(BBL_JSON_KEY_FILAMENT_ID) != preset_values.end()) { if ((m_type == Preset::TYPE_FILAMENT) && preset_values.find(BBL_JSON_KEY_FILAMENT_ID) != preset_values.end()) {
cloud_filament_id = preset_values[BBL_JSON_KEY_FILAMENT_ID]; cloud_filament_id = preset_values[BBL_JSON_KEY_FILAMENT_ID];
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << canonical_name << " filament_id: " << cloud_filament_id << " base_id: " << based_id; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << canonical_name << " filament_id: " << cloud_filament_id << " base_id: " << cloud_base_id;
} }
DynamicPrintConfig new_config, cloud_config; DynamicPrintConfig new_config, cloud_config;
@@ -2273,7 +2271,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
iter->version = cloud_version.value(); iter->version = cloud_version.value();
iter->user_id = cloud_user_id; iter->user_id = cloud_user_id;
iter->setting_id = cloud_setting_id; iter->setting_id = cloud_setting_id;
iter->base_id = based_id; iter->base_id = cloud_base_id;
iter->filament_id = cloud_filament_id; iter->filament_id = cloud_filament_id;
update_alias(*iter); update_alias(*iter);
//presets_loaded.emplace_back(*it->second); //presets_loaded.emplace_back(*it->second);
@@ -2292,7 +2290,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
preset.version = cloud_version.value(); preset.version = cloud_version.value();
preset.user_id = cloud_user_id; preset.user_id = cloud_user_id;
preset.setting_id = cloud_setting_id; preset.setting_id = cloud_setting_id;
preset.base_id = based_id; preset.base_id = cloud_base_id;
preset.filament_id = cloud_filament_id; preset.filament_id = cloud_filament_id;
update_alias(preset); update_alias(preset);
@@ -3653,22 +3651,20 @@ void PresetCollection::set_custom_preset_alias(Preset &preset)
// For printers, there is nothing to remove // For printers, there is nothing to remove
// For prints AKA processes, the postfix should be kept // For prints AKA processes, the postfix should be kept
// Alias should be set here, as the preset name may be augmented further later (i.e., prefixing relative path for bundles) // Alias should be set here, as the preset name may be augmented further later (i.e., prefixing relative path for bundles)
std::string bare_preset_name = get_preset_bare_name(preset.name); std::string alias_name;
std::string alias_name = bare_preset_name; std::string preset_name = get_preset_bare_name(preset.name);
if (m_type == Preset::Type::TYPE_FILAMENT && preset.config.has(BBL_JSON_KEY_INHERITS) && preset.config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS)->value.empty()) {
const bool is_root_filament_preset = if (alias_name.empty()) {
m_type == Preset::Type::TYPE_FILAMENT && size_t end_pos = preset_name.find_first_of("@");
preset.config.has(BBL_JSON_KEY_INHERITS) && if (end_pos != std::string::npos) {
preset.config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS)->value.empty(); alias_name = preset_name.substr(0, end_pos);
if (is_root_filament_preset) {
const size_t suffix_separator_pos = bare_preset_name.find_first_of("@");
if (suffix_separator_pos != std::string::npos) {
alias_name = bare_preset_name.substr(0, suffix_separator_pos);
boost::trim_right(alias_name); boost::trim_right(alias_name);
if (alias_name.empty())
alias_name = bare_preset_name;
} }
} }
}
else {
alias_name = preset_name;
}
preset.alias = std::move(alias_name); preset.alias = std::move(alias_name);
m_map_alias_to_profile_name[preset.alias].push_back(preset.name); m_map_alias_to_profile_name[preset.alias].push_back(preset.name);

View File

@@ -606,25 +606,14 @@ VendorType PresetBundle::get_current_vendor_type()
{ {
auto t = VendorType::Unknown; auto t = VendorType::Unknown;
auto config = &printers.get_edited_preset().config; auto config = &printers.get_edited_preset().config;
const auto* printer_model = config->opt<ConfigOptionString>("printer_model");
if (printer_model == nullptr) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": printer_model is "
<< (config->has("printer_model") ? "not a string" : "missing")
<< ", vendor type is Unknown";
return t;
}
std::string vendor_name; std::string vendor_name;
for (const auto& vendor_profile : vendors) { for (auto vendor_profile : vendors) {
for (const auto& vendor_model : vendor_profile.second.models) { for (auto vendor_model : vendor_profile.second.models)
if (vendor_model.name == printer_model->value) { if (vendor_model.name == config->opt_string("printer_model")) {
vendor_name = vendor_profile.first; vendor_name = vendor_profile.first;
break; break;
} }
} }
if (!vendor_name.empty())
break;
}
if (!vendor_name.empty()) if (!vendor_name.empty())
{ {
if(vendor_name.compare("BBL") == 0) if(vendor_name.compare("BBL") == 0)
@@ -3790,17 +3779,7 @@ int PresetBundle::get_printer_extruder_count() const
{ {
const Preset& printer_preset = this->printers.get_edited_preset(); const Preset& printer_preset = this->printers.get_edited_preset();
const auto* nozzle_diameter = printer_preset.config.option<ConfigOptionFloats>("nozzle_diameter"); int count = printer_preset.config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
if (nozzle_diameter == nullptr) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": nozzle_diameter is missing, using 1 extruder";
return 1;
}
if (nozzle_diameter->values.empty()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": nozzle_diameter is empty, using 1 extruder";
return 1;
}
int count = int(nozzle_diameter->values.size());
return count; return count;
} }

View File

@@ -1,7 +1,4 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <exception>
#include "DevManager.h" #include "DevManager.h"
#include "DevUtil.h" #include "DevUtil.h"
@@ -154,15 +151,11 @@ namespace Slic3r
{ {
keep_alive(); keep_alive();
MachineObject* obj = this->get_selected_machine(); MachineObject* obj = this->get_selected_machine();
if (!obj) {
BOOST_LOG_TRIVIAL(warning) << "DeviceManager::check_pushing selected machine not found";
return;
}
std::chrono::system_clock::time_point start = std::chrono::system_clock::now(); std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
auto internal = std::chrono::duration_cast<std::chrono::milliseconds>(start - obj->last_update_time); auto internal = std::chrono::duration_cast<std::chrono::milliseconds>(start - obj->last_update_time);
if (!obj->is_support_mqtt_alive) if (obj && !obj->is_support_mqtt_alive)
{ {
if (internal.count() > TIMEOUT_FOR_STRAT && internal.count() < 1000 * 60 * 60 * 300) if (internal.count() > TIMEOUT_FOR_STRAT && internal.count() < 1000 * 60 * 60 * 300)
{ {
@@ -923,33 +916,18 @@ namespace Slic3r
const auto cloud_provider = Slic3r::GUI::wxGetApp().get_printer_cloud_provider(); const auto cloud_provider = Slic3r::GUI::wxGetApp().get_printer_cloud_provider();
if (Slic3r::GUI::wxGetApp().is_user_login(cloud_provider)) if (Slic3r::GUI::wxGetApp().is_user_login(cloud_provider))
{ {
try {
m_manager->check_pushing(); m_manager->check_pushing();
} catch (const std::exception& e) { try
BOOST_LOG_TRIVIAL(error) << "DeviceManagerRefresher::on_timer check_pushing exception=" {
<< e.what();
} catch (...) {
BOOST_LOG_TRIVIAL(error) << "DeviceManagerRefresher::on_timer check_pushing unknown exception";
}
try {
agent->refresh_connection(cloud_provider); agent->refresh_connection(cloud_provider);
} catch (const std::exception& e) { }
BOOST_LOG_TRIVIAL(error) << "DeviceManagerRefresher::on_timer refresh_connection exception=" catch (...)
<< e.what(); {
} catch (...) { ;
BOOST_LOG_TRIVIAL(error) << "DeviceManagerRefresher::on_timer refresh_connection unknown exception";
} }
} }
// certificate // certificate
try {
agent->install_device_cert(obj->get_dev_id(), obj->is_lan_mode_printer()); agent->install_device_cert(obj->get_dev_id(), obj->is_lan_mode_printer());
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "DeviceManagerRefresher::on_timer install_device_cert exception="
<< e.what();
} catch (...) {
BOOST_LOG_TRIVIAL(error) << "DeviceManagerRefresher::on_timer install_device_cert unknown exception";
}
} }
} }

View File

@@ -338,7 +338,15 @@ void FilamentGroupPopup::OnRadioBtn(int idx)
} }
} }
void FilamentGroupPopup::OnTimer(wxTimerEvent &event) { Dismiss(); } void FilamentGroupPopup::OnTimer(wxTimerEvent&)
{
if (IsMouseInPopup()) {
StartTimer();
return;
}
Dismiss();
}
void FilamentGroupPopup::Dismiss() { void FilamentGroupPopup::Dismiss() {
m_active = false; m_active = false;
@@ -348,19 +356,22 @@ void FilamentGroupPopup::Dismiss() {
void FilamentGroupPopup::OnLeaveWindow(wxMouseEvent &) void FilamentGroupPopup::OnLeaveWindow(wxMouseEvent &)
{ {
wxPoint pos = this->ScreenToClient(wxGetMousePosition()); if (this->GetScreenRect().Contains(wxGetMousePosition())) return;
if (this->GetClientRect().Contains(pos)) return;
StartTimer(); StartTimer();
} }
void FilamentGroupPopup::OnEnterWindow(wxMouseEvent &) void FilamentGroupPopup::OnEnterWindow(wxMouseEvent &)
{ {
// Ignore spurious ENTER synthesized by PopupWindow::OnMouseEvent2 on macOS. // Ignore spurious ENTER synthesized by PopupWindow::OnMouseEvent2 on macOS.
wxPoint pos = this->ScreenToClient(wxGetMousePosition()); if (!this->GetScreenRect().Contains(wxGetMousePosition())) return;
if (!this->GetClientRect().Contains(pos)) return;
ResetTimer(); ResetTimer();
} }
bool FilamentGroupPopup::IsMouseInPopup() const
{
return this->GetScreenRect().Contains(wxGetMousePosition());
}
void FilamentGroupPopup::UpdateButtonStatus(int hover_idx) void FilamentGroupPopup::UpdateButtonStatus(int hover_idx)
{ {
for (int i = 0; i < ButtonType::btCount; ++i) { for (int i = 0; i < ButtonType::btCount; ++i) {

View File

@@ -36,6 +36,7 @@ private:
void OnEnterWindow(wxMouseEvent &); void OnEnterWindow(wxMouseEvent &);
void OnTimer(wxTimerEvent &event); void OnTimer(wxTimerEvent &event);
void Dismiss(); void Dismiss();
bool IsMouseInPopup() const;
void CreateBmps(); void CreateBmps();

View File

@@ -5851,10 +5851,6 @@ void GUI_App::reload_settings()
return; return;
} }
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " cloud user preset number is: " << user_presets.size(); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " cloud user preset number is: " << user_presets.size();
auto refresh_synced_ui = [this, user_presets = std::move(user_presets)]() mutable {
if (is_closing() || !preset_bundle || !app_config || !mainframe)
return;
// Check the user presets for any system vendors that need to be installed // Check the user presets for any system vendors that need to be installed
for (auto data : user_presets) { for (auto data : user_presets) {
if (!check_preset_parent_available(data)) if (!check_preset_parent_available(data))
@@ -5863,8 +5859,8 @@ void GUI_App::reload_settings()
load_pending_vendors(); load_pending_vendors();
preset_bundle->load_user_presets(*app_config, user_presets, ForwardCompatibilitySubstitutionRule::Enable); preset_bundle->load_user_presets(*app_config, user_presets, ForwardCompatibilitySubstitutionRule::Enable);
preset_bundle->save_user_presets(*app_config, get_delete_cache_presets()); preset_bundle->save_user_presets(*app_config, get_delete_cache_presets());
// Orca: settings changed, refresh ui to reflect the new preset values // Orca: settings changed, refresh ui to reflect the new preset values
auto refresh_synced_ui = [this] {
mainframe->update_side_preset_ui(); mainframe->update_side_preset_ui();
for (auto tab : tabs_list) { for (auto tab : tabs_list) {
tab->reload_config(); tab->reload_config();

View File

@@ -664,14 +664,6 @@ void ParamsPanel::update_mode()
sync_mode_view(m_mode_view); sync_mode_view(m_mode_view);
sync_mode_view(m_current_tab ? dynamic_cast<Tab*>(m_current_tab)->m_mode_view : nullptr); sync_mode_view(m_current_tab ? dynamic_cast<Tab*>(m_current_tab)->m_mode_view : nullptr);
auto sync_mode_icon = [&](ScalableButton* mode_icon) {
if (mode_icon == nullptr)
return;
mode_icon->Show(app_mode != comDevelop);
};
sync_mode_icon(m_mode_icon);
sync_mode_icon(m_current_tab ? dynamic_cast<Tab*>(m_current_tab)->m_mode_icon : nullptr);
} }
void ParamsPanel::msw_rescale() void ParamsPanel::msw_rescale()

View File

@@ -146,6 +146,7 @@ protected:
//BBS: GUI refactor //BBS: GUI refactor
wxPanel* m_top_panel; wxPanel* m_top_panel;
ScalableButton* m_mode_icon; // ORCA m_static_title replacement
wxBoxSizer* m_main_sizer; wxBoxSizer* m_main_sizer;
wxBoxSizer* m_top_sizer; wxBoxSizer* m_top_sizer;
wxBoxSizer* m_top_left_sizer; wxBoxSizer* m_top_left_sizer;
@@ -306,7 +307,6 @@ public:
int m_update_cnt = 0; int m_update_cnt = 0;
ModeSwitchButton *m_mode_view = nullptr; ModeSwitchButton *m_mode_view = nullptr;
ScalableButton* m_mode_icon = nullptr; // ORCA m_static_title replacement
SwitchButton *m_extruder_switch = nullptr; SwitchButton *m_extruder_switch = nullptr;
MultiSwitchButton *m_variant_combo = nullptr; MultiSwitchButton *m_variant_combo = nullptr;

View File

@@ -42,8 +42,7 @@ static std::map<wxColour, wxColour> gDarkColors{
{"#D7E8DE", "#1F2B27"}, // rgb(215, 232, 222) Not Used anymore // Leftover from BBS {"#D7E8DE", "#1F2B27"}, // rgb(215, 232, 222) Not Used anymore // Leftover from BBS
{"#2B3436", "#808080"}, // rgb(43, 52, 54) Not Used anymore // Leftover from BBS. Was used as main fill color of icons {"#2B3436", "#808080"}, // rgb(43, 52, 54) Not Used anymore // Leftover from BBS. Was used as main fill color of icons
{"#ABABAB", "#ABABAB"}, {"#ABABAB", "#ABABAB"},
{"#D9D9D9", "#27272A"}, // rgb(217, 217, 217) Sidebar > Toggle button track color {"#D9D9D9", "#2D2D32"}, // rgb(217, 217, 217) Sidebar > Toggle button track color
{"#FFFEFE", "#D9D9D9"}, // rgb(255, 254, 254) Sidebar > Toggle button thumb color
{"#EBF9F0", "#293F34"}, {"#EBF9F0", "#293F34"},
//{"#F0F0F0", "#4C4C54"}, //{"#F0F0F0", "#4C4C54"},
// ORCA // ORCA

View File

@@ -193,18 +193,20 @@ void StaticBox::doRender(wxDC& dc)
if ((border_width && border_color.count() > 0) || background_color.count() > 0) { if ((border_width && border_color.count() > 0) || background_color.count() > 0) {
wxRect rc(0, 0, size.x, size.y); wxRect rc(0, 0, size.x, size.y);
if (border_width && border_color.count() > 0) { if (border_width && border_color.count() > 0) {
const double scale = dc.GetContentScaleFactor(); if (dc.GetContentScaleFactor() == 1.0) {
int d = floor(border_width / 2.0);
// Snap rect edges to physical pixel boundaries so the 1px pen doesn't straddle a pixel boundary int d2 = floor(border_width - 1);
auto snap = [&](int logical) -> int { rc.x += d;
return (int)(ceil(logical * scale) / scale); rc.width -= d2;
}; rc.y += d;
rc.height -= d2;
int deflate = snap(border_width / 2.0); // at 175%: snap(0.5) = snap→1/1.75 ≈ 1 } else {
rc.x += deflate; int d = 1;
rc.y += deflate; rc.x += d;
rc.width -= deflate * 2; rc.width -= d;
rc.height -= deflate * 2; rc.y += d;
rc.height -= d;
}
dc.SetPen(wxPen(border_color.colorForStates(states), border_width, border_style)); dc.SetPen(wxPen(border_color.colorForStates(states), border_width, border_style));
} else { } else {
dc.SetPen(wxPen(background_color.colorForStates(states))); dc.SetPen(wxPen(background_color.colorForStates(states)));

View File

@@ -220,40 +220,14 @@ void SwitchButton::update()
ModeSwitchButton::ModeSwitchButton(wxWindow* parent, wxWindowID id) ModeSwitchButton::ModeSwitchButton(wxWindow* parent, wxWindowID id)
{ {
background_color = StateColor( background_color = StateColor(
std::make_pair(wxColour("#D9D9D9"), (int) StateColor::Disabled), std::make_pair(wxColour(0xF1, 0xF1, 0xF1), (int) StateColor::Disabled),
std::make_pair(wxColour("#D9D9D9"), (int) StateColor::Normal) std::make_pair(wxColour(0xE3, 0xE3, 0xE3), (int) StateColor::Pressed),
); std::make_pair(wxColour(0xD9, 0xD9, 0xD9), (int) StateColor::Normal));
border_color = StateColor( border_color = StateColor(
std::make_pair(wxColour("#D9D9D9"), (int) StateColor::Disabled), std::make_pair(wxColour(0xEA, 0xEA, 0xEA), (int) StateColor::Disabled),
std::make_pair(wxColour("#D9D9D9"), (int) StateColor::Hovered | ~StateColor::Focused), std::make_pair(wxColour(0xBC, 0xBC, 0xBC), (int) StateColor::Hovered),
std::make_pair(wxColour("#26A69A"), (int) StateColor::Focused), std::make_pair(wxColour(0xC8, 0xC8, 0xC8), (int) StateColor::Focused),
std::make_pair(wxColour("#D9D9D9"), (int) StateColor::Normal) std::make_pair(wxColour(0xCE, 0xCE, 0xCE), (int) StateColor::Normal));
);
track_background = StateColor(
std::make_pair(wxColour("#009688"), (int) StateColor::Disabled),
std::make_pair(wxColour("#009688"), (int) StateColor::Normal)
);
track_border = StateColor(
std::make_pair(wxColour("#D9D9D9"), (int) StateColor::Disabled),
std::make_pair(wxColour("#009688"), (int) StateColor::Hovered | ~StateColor::Focused),
std::make_pair(wxColour("#26A69A"), (int) StateColor::Focused),
std::make_pair(wxColour("#009688"), (int) StateColor::Normal)
);
dot_active = StateColor(
std::make_pair(wxColour("#FFFEFE"), (int) StateColor::Disabled),
std::make_pair(wxColour("#FFFEFE"), (int) StateColor::Normal)
);
dot_dimmed = StateColor(
std::make_pair(wxColour("#EEEEEE"), (int) StateColor::Disabled),
std::make_pair(wxColour("#EEEEEE"), (int) StateColor::Normal)
);
text_color = StateColor(
std::make_pair(wxColour("#6B6B6B"), (int) StateColor::Disabled),
std::make_pair(wxColour("#6B6B6B"), (int) StateColor::Normal)
);
state_handler.attach(std::vector<StateColor const*>{&dot_active, &dot_dimmed, &text_color});
state_handler.update_binds();
StaticBox::Create(parent, id, wxDefaultPosition, wxDefaultSize, 0); StaticBox::Create(parent, id, wxDefaultPosition, wxDefaultSize, 0);
SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent)); SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent));
@@ -289,7 +263,7 @@ void ModeSwitchButton::SelectAndNotify(int selection)
void ModeSwitchButton::Rescale() void ModeSwitchButton::Rescale()
{ {
const wxSize button_size = FromDIP(wxSize(48, 18)); const wxSize button_size = FromDIP(wxSize(48, 20));
SetMinSize(button_size); SetMinSize(button_size);
SetMaxSize(button_size); SetMaxSize(button_size);
SetSize(button_size); SetSize(button_size);
@@ -300,70 +274,63 @@ void ModeSwitchButton::Rescale()
bool ModeSwitchButton::Enable(bool enable /* = true */) bool ModeSwitchButton::Enable(bool enable /* = true */)
{ {
const bool changed = StaticBox::Enable(enable); const bool changed = StaticBox::Enable(enable);
if (changed){ if (changed)
wxCommandEvent e(EVT_ENABLE_CHANGED);
e.SetEventObject(this);
GetEventHandler()->ProcessEvent(e);
m_enabled = enable; // IsEnabled() not works because variable changes after paint event
Refresh(); Refresh();
}
return changed; return changed;
} }
void ModeSwitchButton::doRender(wxDC& dc) void ModeSwitchButton::doRender(wxDC& dc)
{ {
const wxRect bounds = GetClientRect(); dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(GetBackgroundColour()));
dc.DrawRectangle(GetClientRect());
const wxRect bounds = GetClientRect().Deflate(1);
if (bounds.width <= 0 || bounds.height <= 0) if (bounds.width <= 0 || bounds.height <= 0)
return; return;
const int states = state_handler.states();
const bool hovered = (states & StateHandler::Hovered) != 0;
const bool focused = (states & StateHandler::Focused) != 0;
const bool disabled = !IsEnabled();
const wxColour track_fill = disabled ? wxColour(0xD0, 0xD0, 0xD4) :
m_pressed ? wxColour(0x5A, 0x5D, 0x64) : wxColour(0x66, 0x69, 0x70);
const wxColour track_border = disabled ? wxColour(0xDD, 0xDD, 0xE0) :
focused ? wxColour("#009688") :
hovered ? wxColour(0x7A, 0x7D, 0x84) : wxColour(0x75, 0x78, 0x7F);
const wxColour active_fill = disabled ? wxColour(0x9E, 0xBE, 0xB9) :
m_pressed ? wxColour(0x00877B) : wxColour("#009688");
const wxColour active_dot = disabled ? wxColour(0xEC, 0xF4, 0xF2) : wxColour(0xB7, 0xEB, 0xE3);
const wxColour inactive_dot = disabled ? wxColour(0xF2, 0xF2, 0xF4) : wxColour(0xB5, 0xB7, 0xBD);
const wxColour thumb_fill = disabled ? wxColour(0xFA, 0xFA, 0xFA) : *wxWHITE;
const wxColour thumb_border = disabled ? wxColour(0xE7, 0xE7, 0xEA) : wxColour(0xDD, 0xDF, 0xE3);
dc.SetPen(wxPen(track_border, 1));
dc.SetBrush(wxBrush(track_fill));
dc.DrawRoundedRectangle(bounds, bounds.height / 2.0);
const wxRect thumb = thumb_rect_for(m_selection);
const int fill_right = std::min(bounds.GetRight(), thumb.GetX() + thumb.GetWidth() / 2 + FromDIP(2));
wxRect active(bounds.x, bounds.y, fill_right - bounds.x + 1, bounds.height);
dc.SetPen(*wxTRANSPARENT_PEN); dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(GetBackgroundColour())); dc.SetBrush(wxBrush(active_fill));
dc.DrawRectangle(bounds); dc.DrawRoundedRectangle(active, bounds.height / 2.0);
int states = state_handler.states(); const int dot_radius = std::max(FromDIP(1), thumb.height / 7);
double v_center = bounds.height / 2.0;
// Background
dc.SetPen(wxPen(border_color.colorForStates(states), 1));
dc.SetBrush(wxBrush(background_color.colorForStates(states)));
dc.DrawRoundedRectangle(bounds, v_center);
if (m_enabled) {
double dot_dist = (bounds.width - bounds.height) * 0.50;
// Track
dc.SetPen(wxPen(track_border.colorForStates(states), 1));
dc.SetBrush(wxBrush(track_background.colorForStates(states)));
wxRect track_rc = bounds;
track_rc.width = int(v_center * 2.0 + dot_dist * m_selection);
dc.DrawRoundedRectangle(track_rc, v_center);
// Dots
dc.SetPen(*wxTRANSPARENT_PEN);
for (int idx = 0; idx < 3; ++idx) { for (int idx = 0; idx < 3; ++idx) {
dc.SetBrush(wxBrush((idx <= m_selection ? dot_active : dot_dimmed).colorForStates(states))); if (idx == m_selection)
dc.DrawCircle(wxPoint(v_center + dot_dist * idx, v_center), track_rc.height * (double)(idx == m_selection ? 0.32 : 0.16)); continue;
}
}
else { // Developer mode
wxString str = "DEV";
int kerning = 3; // pixels between chars
dc.SetTextForeground(text_color.colorForStates(states));
wxCoord totalWidth = 0; const wxRect slot = thumb_rect_for(idx);
for (char c : str) const wxPoint center(slot.GetX() + slot.GetWidth() / 2, slot.GetY() + slot.GetHeight() / 2);
totalWidth += dc.GetTextExtent(wxString(c)).x + kerning; dc.SetBrush(wxBrush(idx < m_selection ? active_dot : inactive_dot));
totalWidth -= kerning; dc.DrawCircle(center, dot_radius);
wxCoord x = bounds.x + (bounds.width - totalWidth) / 2;
wxCoord y = bounds.y + (bounds.height - dc.GetTextExtent(str).y) / 2 - 1;
for (char c : str) {
wxString ch(c);
dc.DrawText(ch, x, y);
x += dc.GetTextExtent(ch).x + kerning;
}
} }
dc.SetPen(wxPen(thumb_border, 1));
dc.SetBrush(wxBrush(thumb_fill));
dc.DrawRoundedRectangle(thumb, thumb.height / 2.0);
} }
void ModeSwitchButton::mouseDown(wxMouseEvent& event) void ModeSwitchButton::mouseDown(wxMouseEvent& event)

View File

@@ -78,13 +78,7 @@ private:
private: private:
int m_selection { 0 }; int m_selection { 0 };
bool m_pressed { false }; bool m_pressed { false };
bool m_enabled { true };
wxString m_tooltips[3]; wxString m_tooltips[3];
StateColor dot_active;
StateColor dot_dimmed;
StateColor text_color;
StateColor track_background;
StateColor track_border;
}; };
class MultiSwitchButton : public StaticBox class MultiSwitchButton : public StaticBox

View File

@@ -100,33 +100,3 @@ TEST_CASE("Legacy bundle import without bundle metadata stays in the user preset
CHECK(fs::equivalent(fs::path(imported->file).parent_path().parent_path(), user_root / PRESET_PRINT_NAME)); CHECK(fs::equivalent(fs::path(imported->file).parent_path().parent_path(), user_root / PRESET_PRINT_NAME));
} }
TEST_CASE("Current vendor type tolerates missing printer model", "[Preset][Bundle]")
{
PresetBundle bundle;
VendorProfile orca_vendor("ORCA");
VendorProfile::PrinterModel model;
model.name = "Orca Test";
orca_vendor.models.emplace_back(model);
bundle.vendors.emplace("ORCA", std::move(orca_vendor));
bundle.printers.get_edited_preset().config.erase("printer_model");
CHECK(bundle.get_current_vendor_type() == VendorType::Unknown);
}
TEST_CASE("Printer extruder count tolerates missing nozzle diameter", "[Preset][Bundle]")
{
PresetBundle bundle;
DynamicPrintConfig& config = bundle.printers.get_edited_preset().config;
config.erase("nozzle_diameter");
CHECK(bundle.get_printer_extruder_count() == 1);
config.set_key_value("nozzle_diameter", new ConfigOptionFloats());
CHECK(bundle.get_printer_extruder_count() == 1);
config.set_key_value("nozzle_diameter", new ConfigOptionFloats({ 0.4, 0.6 }));
CHECK(bundle.get_printer_extruder_count() == 2);
}