Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cura/Machines/MachineErrorChecker.py64
-rw-r--r--plugins/DigitalLibrary/src/DigitalFactoryController.py73
-rw-r--r--plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml6
-rw-r--r--resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml3
-rw-r--r--resources/qml/PrintSetupTooltip.qml11
-rw-r--r--resources/qml/Settings/SettingView.qml36
-rw-r--r--resources/texts/change_log.txt67
7 files changed, 144 insertions, 116 deletions
diff --git a/cura/Machines/MachineErrorChecker.py b/cura/Machines/MachineErrorChecker.py
index bfefe80fa5..2bc8a6bc58 100644
--- a/cura/Machines/MachineErrorChecker.py
+++ b/cura/Machines/MachineErrorChecker.py
@@ -53,6 +53,8 @@ class MachineErrorChecker(QObject):
self._keys_to_check = set() # type: Set[str]
+ self._num_keys_to_check_per_update = 10
+
def initialize(self) -> None:
self._error_check_timer.timeout.connect(self._rescheduleCheck)
@@ -162,37 +164,37 @@ class MachineErrorChecker(QObject):
self._check_in_progress = True
- # If there is nothing to check any more, it means there is no error.
- if not self._stacks_and_keys_to_check:
- # Finish
- self._setResult(False)
- return
-
- # Get the next stack and key to check
- stack, key = self._stacks_and_keys_to_check.popleft()
-
- enabled = stack.getProperty(key, "enabled")
- if not enabled:
- self._application.callLater(self._checkStack)
- return
-
- validation_state = stack.getProperty(key, "validationState")
- if validation_state is None:
- # Setting is not validated. This can happen if there is only a setting definition.
- # We do need to validate it, because a setting definitions value can be set by a function, which could
- # be an invalid setting.
- definition = stack.getSettingDefinition(key)
- validator_type = SettingDefinition.getValidatorForType(definition.type)
- if validator_type:
- validator = validator_type(key)
- validation_state = validator(stack)
- if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError, ValidatorState.Invalid):
- # Since we don't know if any of the settings we didn't check is has an error value, store the list for the
- # next check.
- keys_to_recheck = {setting_key for stack, setting_key in self._stacks_and_keys_to_check}
- keys_to_recheck.add(key)
- self._setResult(True, keys_to_recheck = keys_to_recheck)
- return
+ for i in range(self._num_keys_to_check_per_update):
+ # If there is nothing to check any more, it means there is no error.
+ if not self._stacks_and_keys_to_check:
+ # Finish
+ self._setResult(False)
+ return
+
+ # Get the next stack and key to check
+ stack, key = self._stacks_and_keys_to_check.popleft()
+
+ enabled = stack.getProperty(key, "enabled")
+ if not enabled:
+ continue
+
+ validation_state = stack.getProperty(key, "validationState")
+ if validation_state is None:
+ # Setting is not validated. This can happen if there is only a setting definition.
+ # We do need to validate it, because a setting definitions value can be set by a function, which could
+ # be an invalid setting.
+ definition = stack.getSettingDefinition(key)
+ validator_type = SettingDefinition.getValidatorForType(definition.type)
+ if validator_type:
+ validator = validator_type(key)
+ validation_state = validator(stack)
+ if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError, ValidatorState.Invalid):
+ # Since we don't know if any of the settings we didn't check is has an error value, store the list for the
+ # next check.
+ keys_to_recheck = {setting_key for stack, setting_key in self._stacks_and_keys_to_check}
+ keys_to_recheck.add(key)
+ self._setResult(True, keys_to_recheck = keys_to_recheck)
+ continue
# Schedule the check for the next key
self._application.callLater(self._checkStack)
diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py
index fa6c63e1dc..cee367e188 100644
--- a/plugins/DigitalLibrary/src/DigitalFactoryController.py
+++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py
@@ -10,7 +10,7 @@ from enum import IntEnum
from pathlib import Path
from typing import Optional, List, Dict, Any, cast
-from PyQt6.QtCore import pyqtSignal, QObject, pyqtSlot, pyqtProperty, pyqtEnum, QTimer, QUrl
+from PyQt6.QtCore import pyqtSignal, QObject, pyqtSlot, pyqtProperty, pyqtEnum, QTimer, QUrl, QMetaObject
from PyQt6.QtNetwork import QNetworkReply
from PyQt6.QtQml import qmlRegisterType, qmlRegisterUncreatableMetaObject
@@ -32,26 +32,6 @@ from .DigitalFactoryProjectModel import DigitalFactoryProjectModel
from .DigitalFactoryProjectResponse import DigitalFactoryProjectResponse
-class RetrievalStatus(IntEnum):
- """
- The status of an http get request.
-
- This is not an enum, because we want to use it in QML and QML doesn't recognize Python enums.
- """
- Idle = 0
- InProgress = 1
- Success = 2
- Failed = 3
-
-
-class DFRetrievalStatus(QObject):
- """
- Used as an intermediate QObject that registers the RetrievalStatus as a recognizable enum in QML, so that it can
- be used within QML objects as DigitalFactory.RetrievalStatus.<status>
- """
-
- pyqtEnum(RetrievalStatus)
-
class DigitalFactoryController(QObject):
@@ -98,6 +78,19 @@ class DigitalFactoryController(QObject):
"""Signal to inform whether the user is allowed to create more Library projects."""
userCanCreateNewLibraryProjectChanged = pyqtSignal(bool)
+ class RetrievalStatus(IntEnum):
+ """
+ The status of an http get request.
+
+ This is not an enum, because we want to use it in QML and QML doesn't recognize Python enums.
+ """
+ Idle = 0
+ InProgress = 1
+ Success = 2
+ Failed = 3
+
+ pyqtEnum(RetrievalStatus)
+
def __init__(self, application: CuraApplication) -> None:
super().__init__(parent = None)
@@ -139,9 +132,9 @@ class DigitalFactoryController(QObject):
self._erase_temp_files_lock = threading.Lock()
# The statuses which indicate whether Cura is waiting for a response from the DigitalFactory API
- self.retrieving_files_status = RetrievalStatus.Idle
- self.retrieving_projects_status = RetrievalStatus.Idle
- self.creating_new_project_status = RetrievalStatus.Idle
+ self.retrieving_files_status = self.RetrievalStatus.Idle
+ self.retrieving_projects_status = self.RetrievalStatus.Idle
+ self.creating_new_project_status = self.RetrievalStatus.Idle
self._application.engineCreatedSignal.connect(self._onEngineCreated)
self._application.initializationFinished.connect(self._applicationInitializationFinished)
@@ -155,9 +148,9 @@ class DigitalFactoryController(QObject):
self._has_preselected_project = False
self.preselectedProjectChanged.emit()
- self.setRetrievingFilesStatus(RetrievalStatus.Idle)
- self.setRetrievingProjectsStatus(RetrievalStatus.Idle)
- self.setCreatingNewProjectStatus(RetrievalStatus.Idle)
+ self.setRetrievingFilesStatus(self.RetrievalStatus.Idle)
+ self.setRetrievingProjectsStatus(self.RetrievalStatus.Idle)
+ self.setCreatingNewProjectStatus(self.RetrievalStatus.Idle)
self.setSelectedProjectIndex(-1)
@@ -182,7 +175,7 @@ class DigitalFactoryController(QObject):
self.clear()
if self._account.isLoggedIn and self.userAccountHasLibraryAccess():
- self.setRetrievingProjectsStatus(RetrievalStatus.InProgress)
+ self.setRetrievingProjectsStatus(self.RetrievalStatus.InProgress)
if preselected_project_id:
self._api.getProject(preselected_project_id, on_finished = self.setProjectAsPreselected, failed = self._onGetProjectFailed)
else:
@@ -199,8 +192,8 @@ class DigitalFactoryController(QObject):
self._project_model.setProjects([df_project])
self.setSelectedProjectIndex(0)
self.setHasPreselectedProject(True)
- self.setRetrievingProjectsStatus(RetrievalStatus.Success)
- self.setCreatingNewProjectStatus(RetrievalStatus.Success)
+ self.setRetrievingProjectsStatus(self.RetrievalStatus.Success)
+ self.setCreatingNewProjectStatus(self.RetrievalStatus.Success)
def _onGetProjectFailed(self, reply: QNetworkReply, error: QNetworkReply.NetworkError) -> None:
reply_string = bytes(reply.readAll()).decode()
@@ -216,7 +209,7 @@ class DigitalFactoryController(QObject):
"""
self.setHasMoreProjectsToLoad(self._api.hasMoreProjectsToLoad())
self._project_model.setProjects(df_projects)
- self.setRetrievingProjectsStatus(RetrievalStatus.Success)
+ self.setRetrievingProjectsStatus(self.RetrievalStatus.Success)
@pyqtSlot()
def loadMoreProjects(self) -> None:
@@ -224,7 +217,7 @@ class DigitalFactoryController(QObject):
Initiates the process of retrieving the next page of the projects list from the API.
"""
self._api.getMoreProjects(on_finished = self.loadMoreProjectsFinished, failed = self._onGetProjectsFailed)
- self.setRetrievingProjectsStatus(RetrievalStatus.InProgress)
+ self.setRetrievingProjectsStatus(self.RetrievalStatus.InProgress)
def loadMoreProjectsFinished(self, df_projects: List[DigitalFactoryProjectResponse]) -> None:
"""
@@ -235,13 +228,13 @@ class DigitalFactoryController(QObject):
"""
self.setHasMoreProjectsToLoad(self._api.hasMoreProjectsToLoad())
self._project_model.extendProjects(df_projects)
- self.setRetrievingProjectsStatus(RetrievalStatus.Success)
+ self.setRetrievingProjectsStatus(self.RetrievalStatus.Success)
def _onGetProjectsFailed(self, reply: QNetworkReply, error: QNetworkReply.NetworkError) -> None:
"""
Error function, called whenever the retrieval of projects fails.
"""
- self.setRetrievingProjectsStatus(RetrievalStatus.Failed)
+ self.setRetrievingProjectsStatus(self.RetrievalStatus.Failed)
Logger.log("w", "Failed to retrieve the list of projects from the Digital Library. Error encountered: {}".format(error))
def getProjectFilesFinished(self, df_files_in_project: List[DigitalFactoryFileResponse]) -> None:
@@ -255,7 +248,7 @@ class DigitalFactoryController(QObject):
# Filter to show only the files that can be opened in Cura
self._file_model.setFilters({"file_name": lambda x: Path(x).suffix[1:].lower() in self._supported_file_types}) # the suffix is in format '.xyz', so omit the dot at the start
self._file_model.setFiles(df_files_in_project)
- self.setRetrievingFilesStatus(RetrievalStatus.Success)
+ self.setRetrievingFilesStatus(self.RetrievalStatus.Success)
def getProjectFilesFailed(self, reply: QNetworkReply, error: QNetworkReply.NetworkError) -> None:
"""
@@ -265,7 +258,7 @@ class DigitalFactoryController(QObject):
Logger.warning(f"Failed to retrieve the list of files in project '{self._project_model._projects[self._selected_project_idx]}' from the Digital Library")
except IndexError:
Logger.warning(f"Failed to retrieve the list of files in a project from the Digital Library. And failed to get the project too.")
- self.setRetrievingFilesStatus(RetrievalStatus.Failed)
+ self.setRetrievingFilesStatus(self.RetrievalStatus.Failed)
@pyqtSlot()
def clearProjectSelection(self) -> None:
@@ -297,7 +290,7 @@ class DigitalFactoryController(QObject):
self.selectedFileIndicesChanged.emit([])
if 0 <= project_idx < len(self._project_model.items):
library_project_id = self._project_model.items[project_idx]["libraryProjectId"]
- self.setRetrievingFilesStatus(RetrievalStatus.InProgress)
+ self.setRetrievingFilesStatus(self.RetrievalStatus.InProgress)
self._api.getListOfFilesInProject(library_project_id, on_finished = self.getProjectFilesFinished, failed = self.getProjectFilesFailed)
@pyqtProperty(int, fset = setSelectedProjectIndex, notify = selectedProjectIndexChanged)
@@ -381,7 +374,7 @@ class DigitalFactoryController(QObject):
"""
if project_name:
self._api.createNewProject(project_name, self.setProjectAsPreselected, self._createNewLibraryProjectFailed)
- self.setCreatingNewProjectStatus(RetrievalStatus.InProgress)
+ self.setCreatingNewProjectStatus(self.RetrievalStatus.InProgress)
else:
Logger.log("w", "No project name provided while attempting to create a new project. Aborting the project creation.")
@@ -395,7 +388,7 @@ class DigitalFactoryController(QObject):
self._project_creation_error_text = "Error while creating the new project: {}".format(reply_dict["errors"][0]["title"])
self.projectCreationErrorTextChanged.emit()
- self.setCreatingNewProjectStatus(RetrievalStatus.Failed)
+ self.setCreatingNewProjectStatus(self.RetrievalStatus.Failed)
Logger.log("e", "Something went wrong while trying to create a new a project. Error: {}".format(reply_string))
def setRetrievingProjectsStatus(self, new_status: RetrievalStatus) -> None:
@@ -565,7 +558,7 @@ class DigitalFactoryController(QObject):
self.setSelectedProjectIndex(-1)
self._api.getProjectsFirstPage(search_filter = self._project_filter, on_finished = self._onGetProjectsFirstPageFinished, failed = self._onGetProjectsFailed)
self._api.checkUserCanCreateNewLibraryProject(callback = self.setCanCreateNewLibraryProject)
- self.setRetrievingProjectsStatus(RetrievalStatus.InProgress)
+ self.setRetrievingProjectsStatus(self.RetrievalStatus.InProgress)
self._has_preselected_project = new_has_preselected_project
self.preselectedProjectChanged.emit()
diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml
index 397710114e..2d4b3e01e5 100644
--- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml
+++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml
@@ -196,7 +196,7 @@ Item
height: parent.height
width: UM.Theme.getSize("setting").width + UM.Theme.getSize("default_margin").width
- ScrollBar.vertical: UM.ScrollBar {}
+ ScrollBar.vertical: UM.ScrollBar { id: scrollBar }
clip: true
spacing: UM.Theme.getSize("default_lining").height
@@ -244,7 +244,7 @@ Item
Loader
{
id: settingLoader
- width: UM.Theme.getSize("setting").width - removeButton.width
+ width: UM.Theme.getSize("setting").width - removeButton.width - scrollBar.width
height: UM.Theme.getSize("section").height + UM.Theme.getSize("narrow_margin").height
enabled: provider.properties.enabled === "True"
property var definition: model
@@ -299,7 +299,7 @@ Item
{
id: removeButton
width: UM.Theme.getSize("setting").height
- height: UM.Theme.getSize("setting").height
+ height: UM.Theme.getSize("setting").height + UM.Theme.getSize("narrow_margin").height
onClicked: addedSettingsModel.setVisible(model.key, false)
diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml
index 434945e172..863e8c3900 100644
--- a/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml
+++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml
@@ -172,7 +172,8 @@ Item
// same operation
const active_mode = UM.Preferences.getValue("cura/active_mode")
- if (active_mode == 0 || active_mode == "simple")
+ if (visible // Workaround: 'visible' is checked because on startup in Windows it spuriously gets an 'onValueChanged' with value '0' if this isn't checked.
+ && (active_mode == 0 || active_mode == "simple"))
{
Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue)
Cura.MachineManager.resetSettingForAllExtruders("infill_line_distance")
diff --git a/resources/qml/PrintSetupTooltip.qml b/resources/qml/PrintSetupTooltip.qml
index 29fe7d6508..5e5b1dce73 100644
--- a/resources/qml/PrintSetupTooltip.qml
+++ b/resources/qml/PrintSetupTooltip.qml
@@ -11,7 +11,7 @@ UM.PointingRectangle
id: base
property real sourceWidth: 0
width: UM.Theme.getSize("tooltip").width
- height: textScroll.height + UM.Theme.getSize("tooltip_margins").height * 2
+ height: UM.Theme.getSize("tooltip").height
color: UM.Theme.getColor("tooltip")
arrowSize: UM.Theme.getSize("default_arrow").width
@@ -81,12 +81,11 @@ UM.PointingRectangle
ScrollView
{
id: textScroll
- width: parent.width
- height: Math.min(label.height, base.parent.height)
+ width: base.width
+ height: base.height
- ScrollBar.horizontal: ScrollBar {
- active: false //Only allow vertical scrolling. We should grow vertically only, but due to how the label is positioned it allocates space in the ScrollView horizontally.
- }
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+ ScrollBar.vertical.policy: ScrollBar.AsNeeded
UM.Label
{
diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml
index 28787acb27..cf24997b12 100644
--- a/resources/qml/Settings/SettingView.qml
+++ b/resources/qml/Settings/SettingView.qml
@@ -195,7 +195,7 @@ Item
onPositionChanged: {
// This removes focus from items when scrolling.
// This fixes comboboxes staying open and scrolling container
- if (!activeFocus) {
+ if (!activeFocus && !filter.activeFocus) {
forceActiveFocus();
}
}
@@ -227,9 +227,7 @@ Item
id: delegate
width: contents.width - (scrollBar.width + UM.Theme.getSize("narrow_margin").width)
- Behavior on height { NumberAnimation { duration: 100 } }
opacity: enabled ? 1 : 0
- Behavior on opacity { NumberAnimation { duration: 100 } }
enabled: provider.properties.enabled === "True"
property var definition: model
@@ -351,10 +349,7 @@ Item
function onFocusReceived()
{
contents.indexWithFocus = index
- animateContentY.from = contents.contentY
contents.positionViewAtIndex(index, ListView.Contain)
- animateContentY.to = contents.contentY
- animateContentY.running = true
}
function onSetActiveFocusToNextSetting(forward)
{
@@ -386,35 +381,6 @@ Item
}
}
- NumberAnimation {
- id: animateContentY
- target: contents
- property: "contentY"
- duration: 50
- }
-
- add: Transition {
- SequentialAnimation {
- NumberAnimation { properties: "height"; from: 0; duration: 100 }
- NumberAnimation { properties: "opacity"; from: 0; duration: 100 }
- }
- }
- remove: Transition {
- SequentialAnimation {
- NumberAnimation { properties: "opacity"; to: 0; duration: 100 }
- NumberAnimation { properties: "height"; to: 0; duration: 100 }
- }
- }
- addDisplaced: Transition {
- NumberAnimation { properties: "x,y"; duration: 100 }
- }
- removeDisplaced: Transition {
- SequentialAnimation {
- PauseAnimation { duration: 100; }
- NumberAnimation { properties: "x,y"; duration: 100 }
- }
- }
-
Cura.Menu
{
id: contextMenu
diff --git a/resources/texts/change_log.txt b/resources/texts/change_log.txt
index 91d54ef17a..98cc638295 100644
--- a/resources/texts/change_log.txt
+++ b/resources/texts/change_log.txt
@@ -1,3 +1,70 @@
+[5.0]
+Beta
+<i><a href="https://youtu.be/kRj7pR4OkQA">Watch the launch event</a> to learn more about Ultimaker Cura 5.0 beta.</i>
+
+* New slicing engine
+Following special beta releases to test the Arachne engine, we are pleased to announce our new slicing engine is here in Ultimaker Cura! This all-new engine uses variable line widths when preparing files for printing, meaning you can now print thin and intricate parts more accurately and with greater strength.
+
+* Renewed the Ultimaker Cura Marketplace
+We have streamlined the workflow for accessing the Ultimaker Marketplace inside of Ultimaker Cura. The UI has been improved and it’s now easier and faster to find and install plugins and material profiles.
+
+* Improved print profiles for Ultimaker printers
+The new slicing engine in Ultimaker Cura 5.0 beta has helped us to improve our print profiles. This means that users of Ultimaker printers can achieve speed increases of up to 20%.
+
+* Upgrade from Qt5 to Qt6
+We now support Apple M1 chips
+
+* Other new features and improvements:
+- New Cura icon
+- New Cura splash screen
+- Updated the digital build plates for Ultimaker printers
+- Introduce Minimum Wall Line Width, contributed by BagelOrb
+- Settings for metal printing implemented
+- Shrinkage compensation is now available for PLA, tPLA and PETG
+- Improved default Line Widths for Spiralize
+- Decrease resolution to remove some buffer underruns
+- Removed the setting Center Last from Wall Ordering
+- Incomplete languages are now shown in the language drop-down menu
+
+* Bug fixes:
+- Added the Scale Fan Speed From 0 to 1 setting for printers that interpreted fan speed as percentages
+- Fixed a bug with extra travel moves increased the printing time, contributed by BagelOrb
+- Fixed a bug where Monotonic Ironing breaks Ironing, contributed by BagelOrb
+- Changed the priority of CuraEngine
+- Fixed a bug where increasing Filter distances creates extremely wide lines, contributed by BagelOrb
+- Fixed double scroll bar, contributed by fieldOfView
+- Fixed a bug where maximum resolution/deviation was not applied to surface mode, contributed by BagelOrb
+- Fixed a bug where the seam placement was uneven
+- Fixed a bug where Top Surface Skin Layers didn't work
+- Fixed a bug where Speed in the flow setting were not respected
+- Fixed a bug with unnecessary retracted travel moves
+- Fixed a bug where the Ironing Inset didn't work
+- Fixed a bug where Support Layers were missing
+- Improved the visibility of the checkboxes
+- Fixed a crash if Randomize Infill Start was used
+- Fixed a bug where Combing was in the wrong part with dual extrusion
+- Fixed a crash with Bridging and Top Surface Skin Layers
+- Fixed a bug where modifier meshes didn't work in one-at-a-time mode
+- Fixed a bug where Tree Support Branches where not being generated
+- Fixed a bug where less support was generated
+- Changed the possibility for 100% Infill Bottom Layer for Spiralize, contributed by BagelOrb
+- Fixed disallowed areas for Brim gap, contributed by BagelOrb
+
+* Printer definitions, profiles and materials:
+- Added Atom 3 and Atom 3 Lite printer definitions, contributed by Daniel-Kurth
+- Added Layer One Black PLA, Dark Grey PLA and White PLA, contributed by Daniel-Kurth
+- Added FLSUN Q5 printer definition, contributed by kreuzhofer
+- Added Creatlity CR100 printer definition, contributed by bodyboarder2528
+- Added Mixware Hyper-S printer definition, contributed by mixware011
+- Added Creality Sermoon D1 printer definition, contributed by felixstif
+- Added Volumic SH65, Stream30Pro MK3 and Stream30Ultra SC2 printer definitions, contributed by VOLUMIC
+- Updated Eryone Thinker and ER20 profiles, contributed by Eryone
+- Updated Atom 2 profile, contributed by lin-ycv
+- Added Hellbot Hidra and Magna series printer definitions, contributed by DevelopmentHellbot
+- Updated Snapmaker 2 End-Gcode, contributed by Rolzad73
+- Updated the Tinyboy Fabricator printer definitions, contributed by reibuehl
+- Updated the Creality Ender 5 printer profile, contributed by Rakhmanov
+
[4.13.1]
* Bug fixes
- Fixed a bug where tree support could go through the model