mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-01 00:04:27 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
4518132ffc
116
.pylintrc
Normal file
116
.pylintrc
Normal file
@ -0,0 +1,116 @@
|
||||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# This file contains the Pylint rules used in the stardust projects.
|
||||
|
||||
# To configure PyLint as an external tool in PyCharm, create a new External Tool with the settings:
|
||||
#
|
||||
# Name: PyLint
|
||||
# Program: Check with 'which pylint'. For example: ~/.local/bin/pylint
|
||||
# Arguments: $FileDirName$ --rcfile=.pylintrc --msg-template='{abspath}:{line}:{column}:({symbol}):{msg_id}:{msg}'
|
||||
# Working directory: $ContentRoot$
|
||||
# Output filters: $FILE_PATH$:$LINE$:$COLUMN$:.*
|
||||
#
|
||||
# You can add a keyboard shortcut in the keymap settings. To run Pylint to a project, select the module
|
||||
# you want to check (e.g. cura folder) before running the external tool.
|
||||
#
|
||||
# If you find a better way to configure the external tool please edit this file.
|
||||
|
||||
[MASTER]
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=pylint_quotes
|
||||
|
||||
# We expect double string quotes
|
||||
string-quote=double-avoid-escape
|
||||
|
||||
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||
# user-friendly hints instead of false-positive error messages.
|
||||
suggestion-mode=yes
|
||||
|
||||
# Add files or directories to the blacklist. They should be base names, not paths.
|
||||
ignore=tests
|
||||
|
||||
[REFACTORING]
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=5
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
# C0326: No space allowed around keyword argument assignment
|
||||
# C0411: Ignore import order because the rules are different than in PyCharm, so automatic imports break lots of builds
|
||||
# C0412: Ignore import order because the rules are different than in PyCharm, so automatic imports break lots of builds
|
||||
# C0413: Ignore import order because the rules are different than in PyCharm, so automatic imports break lots of builds
|
||||
# R0201: Method could be a function (no-self-use)
|
||||
# R0401: Cyclic imports (cyclic-import) are used for typing
|
||||
# R0801: Unfortunately the error is triggered for a lot of similar models (duplicate-code)
|
||||
# R1710: Either all return statements in a function should return an expression, or none of them should.
|
||||
# W0221: Parameters differ from overridden method (tornado http methods have a flexible number of parameters)
|
||||
# W0511: Ignore warnings generated for TODOs in the code
|
||||
# C0111: We don't use docstring
|
||||
# C0303: Trailing whitespace isn't something we care about
|
||||
# C4001: You can put " in a string if you escape it first...
|
||||
disable=C0326,C0411,C0412,C0413,R0201,R0401,R0801,R1710,W0221,W0511, C0111, C0303,C4001
|
||||
|
||||
[FORMAT]
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=120
|
||||
|
||||
# Maximum number of lines in a module.
|
||||
max-module-lines=500
|
||||
|
||||
good-names=os
|
||||
|
||||
[BASIC]
|
||||
# allow modules and functions to use PascalCase
|
||||
module-rgx=[a-zA-Z0-9_]+$
|
||||
function-rgx=
|
||||
## Allowed methods:
|
||||
# getSomething
|
||||
# _getSomething
|
||||
# __getSomething
|
||||
# __new__
|
||||
## Disallowed:
|
||||
# _GET
|
||||
# GetSomething
|
||||
method-rgx=(_{,2}[a-z][A-Za-z0-9]*_{,2})$
|
||||
|
||||
[DESIGN]
|
||||
# Maximum number of arguments for function / method.
|
||||
max-args=7
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=8
|
||||
|
||||
# Maximum number of boolean expressions in an if statement.
|
||||
max-bool-expr=5
|
||||
|
||||
# Maximum number of branch for function / method body.
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of locals for function / method body.
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of return / yield for function / method body.
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of statements in function / method body.
|
||||
max-statements=50
|
||||
|
||||
# Minimum number of public methods for a class (R0903).
|
||||
# We set this to 0 because our models and fields do not have methods.
|
||||
min-public-methods=0
|
||||
|
||||
ignored-argument-names=arg|args|kwargs|_
|
||||
|
||||
[CLASSES]
|
||||
defining-attr-methods=__init__,__new__,setUp,initialize
|
||||
|
||||
[TYPECHECK]
|
||||
ignored-classes=NotImplemented
|
||||
|
||||
[VARIABLES]
|
||||
dummy-variables-rgx=_+[a-z0-9_]{2,30}
|
@ -1,6 +1,6 @@
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Logger import Logger
|
||||
@ -8,6 +8,7 @@ from UM.Math.Polygon import Polygon
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from cura.Arranging.ShapeArray import ShapeArray
|
||||
from cura.BuildVolume import BuildVolume
|
||||
from cura.Scene import ZOffsetDecorator
|
||||
|
||||
from collections import namedtuple
|
||||
@ -27,7 +28,7 @@ LocationSuggestion = namedtuple("LocationSuggestion", ["x", "y", "penalty_points
|
||||
#
|
||||
# Note: Make sure the scale is the same between ShapeArray objects and the Arrange instance.
|
||||
class Arrange:
|
||||
build_volume = None
|
||||
build_volume = None # type: Optional[BuildVolume]
|
||||
|
||||
def __init__(self, x, y, offset_x, offset_y, scale= 0.5):
|
||||
self._scale = scale # convert input coordinates to arrange coordinates
|
||||
@ -68,7 +69,7 @@ class Arrange:
|
||||
points = copy.deepcopy(vertices._points)
|
||||
|
||||
# After scaling (like up to 0.1 mm) the node might not have points
|
||||
if len(points) == 0:
|
||||
if not points:
|
||||
continue
|
||||
|
||||
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
||||
@ -113,7 +114,7 @@ class Arrange:
|
||||
found_spot = True
|
||||
self.place(x, y, offset_shape_arr) # place the object in arranger
|
||||
else:
|
||||
Logger.log("d", "Could not find spot!"),
|
||||
Logger.log("d", "Could not find spot!")
|
||||
found_spot = False
|
||||
node.setPosition(Vector(200, center_y, 100))
|
||||
return found_spot
|
||||
|
@ -29,7 +29,7 @@ class ArrangeArray:
|
||||
self._has_empty = False
|
||||
self._arrange = [] # type: List[Arrange]
|
||||
|
||||
def _update_first_empty(self):
|
||||
def _updateFirstEmpty(self):
|
||||
for i, a in enumerate(self._arrange):
|
||||
if a.isEmpty:
|
||||
self._first_empty = i
|
||||
@ -42,7 +42,7 @@ class ArrangeArray:
|
||||
new_arrange = Arrange.create(x = self._x, y = self._y, fixed_nodes = self._fixed_nodes)
|
||||
self._arrange.append(new_arrange)
|
||||
self._count += 1
|
||||
self._update_first_empty()
|
||||
self._updateFirstEmpty()
|
||||
|
||||
def count(self):
|
||||
return self._count
|
||||
|
@ -2,12 +2,16 @@
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import QTimer
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
from UM.Logger import Logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from cura.CuraApplication import CuraApplication
|
||||
|
||||
|
||||
class AutoSave:
|
||||
def __init__(self, application):
|
||||
def __init__(self, application: "CuraApplication") -> None:
|
||||
self._application = application
|
||||
self._application.getPreferences().preferenceChanged.connect(self._triggerTimer)
|
||||
|
||||
@ -22,14 +26,14 @@ class AutoSave:
|
||||
self._enabled = True
|
||||
self._saving = False
|
||||
|
||||
def initialize(self):
|
||||
def initialize(self) -> None:
|
||||
# only initialise if the application is created and has started
|
||||
self._change_timer.timeout.connect(self._onTimeout)
|
||||
self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||
self._onGlobalStackChanged()
|
||||
self._triggerTimer()
|
||||
|
||||
def _triggerTimer(self, *args):
|
||||
def _triggerTimer(self, *args: Any) -> None:
|
||||
if not self._saving:
|
||||
self._change_timer.start()
|
||||
|
||||
@ -40,7 +44,7 @@ class AutoSave:
|
||||
else:
|
||||
self._change_timer.stop()
|
||||
|
||||
def _onGlobalStackChanged(self):
|
||||
def _onGlobalStackChanged(self) -> None:
|
||||
if self._global_stack:
|
||||
self._global_stack.propertyChanged.disconnect(self._triggerTimer)
|
||||
self._global_stack.containersChanged.disconnect(self._triggerTimer)
|
||||
@ -51,7 +55,7 @@ class AutoSave:
|
||||
self._global_stack.propertyChanged.connect(self._triggerTimer)
|
||||
self._global_stack.containersChanged.connect(self._triggerTimer)
|
||||
|
||||
def _onTimeout(self):
|
||||
def _onTimeout(self) -> None:
|
||||
self._saving = True # To prevent the save process from triggering another autosave.
|
||||
Logger.log("d", "Autosaving preferences, instances and profiles")
|
||||
|
||||
|
@ -1,15 +1,21 @@
|
||||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import numpy
|
||||
import math
|
||||
|
||||
from typing import List, Optional, TYPE_CHECKING, Any, Set, cast, Iterable, Dict
|
||||
|
||||
from UM.Mesh.MeshData import MeshData
|
||||
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||
|
||||
from UM.Application import Application #To modify the maximum zoom level.
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Scene.Platform import Platform
|
||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Resources import Resources
|
||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Math.Matrix import Matrix
|
||||
from UM.Math.Color import Color
|
||||
@ -17,23 +23,23 @@ from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||
from UM.Math.Polygon import Polygon
|
||||
from UM.Message import Message
|
||||
from UM.Signal import Signal
|
||||
from PyQt5.QtCore import QTimer
|
||||
from UM.View.RenderBatch import RenderBatch
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
|
||||
catalog = i18nCatalog("cura")
|
||||
from PyQt5.QtCore import QTimer
|
||||
|
||||
import numpy
|
||||
import math
|
||||
|
||||
from typing import List, Optional, TYPE_CHECKING, Any, Set, cast, Iterable, Dict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from cura.Settings.ExtruderStack import ExtruderStack
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
# Radius of disallowed area in mm around prime. I.e. how much distance to keep from prime position.
|
||||
PRIME_CLEARANCE = 6.5
|
||||
|
||||
@ -1012,13 +1018,13 @@ class BuildVolume(SceneNode):
|
||||
all_values = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, "value")
|
||||
all_types = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, "type")
|
||||
for i, (setting_value, setting_type) in enumerate(zip(all_values, all_types)):
|
||||
if not setting_value and (setting_type == "int" or setting_type == "float"):
|
||||
if not setting_value and setting_type in ["int", "float"]:
|
||||
all_values[i] = 0
|
||||
return all_values
|
||||
|
||||
def _calculateBedAdhesionSize(self, used_extruders):
|
||||
if self._global_container_stack is None:
|
||||
return
|
||||
return None
|
||||
|
||||
container_stack = self._global_container_stack
|
||||
adhesion_type = container_stack.getProperty("adhesion_type", "value")
|
||||
|
@ -58,6 +58,8 @@ class CrashHandler:
|
||||
self.traceback = tb
|
||||
self.has_started = has_started
|
||||
self.dialog = None # Don't create a QDialog before there is a QApplication
|
||||
self.cura_version = None
|
||||
self.cura_locale = None
|
||||
|
||||
Logger.log("c", "An uncaught error has occurred!")
|
||||
for line in traceback.format_exception(exception_type, value, tb):
|
||||
|
@ -3,17 +3,15 @@
|
||||
|
||||
from PyQt5.QtCore import QObject, QUrl
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
from typing import List, Optional, cast
|
||||
from typing import List, cast
|
||||
|
||||
from UM.Event import CallFunctionEvent
|
||||
from UM.FlameProfiler import pyqtSlot
|
||||
from UM.Math.Quaternion import Quaternion
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
||||
from UM.Operations.RotateOperation import RotateOperation
|
||||
from UM.Operations.TranslateOperation import TranslateOperation
|
||||
|
||||
import cura.CuraApplication
|
||||
|
@ -4,7 +4,7 @@
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from typing import cast, TYPE_CHECKING, Optional, Callable, List
|
||||
from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any
|
||||
|
||||
import numpy
|
||||
|
||||
@ -15,7 +15,7 @@ from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qm
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Application import Application
|
||||
from UM.Decorators import override, deprecated
|
||||
from UM.Decorators import override
|
||||
from UM.FlameProfiler import pyqtSlot
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
@ -193,7 +193,7 @@ class CuraApplication(QtApplication):
|
||||
|
||||
self._cura_package_manager = None
|
||||
|
||||
self._machine_action_manager = None
|
||||
self._machine_action_manager = None # type: Optional[MachineActionManager.MachineActionManager]
|
||||
|
||||
self.empty_container = None # type: EmptyInstanceContainer
|
||||
self.empty_definition_changes_container = None # type: EmptyInstanceContainer
|
||||
@ -266,7 +266,6 @@ class CuraApplication(QtApplication):
|
||||
# Backups
|
||||
self._auto_save = None # type: Optional[AutoSave]
|
||||
|
||||
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
|
||||
self._container_registry_class = CuraContainerRegistry
|
||||
# Redefined here in order to please the typing.
|
||||
self._container_registry = None # type: CuraContainerRegistry
|
||||
@ -699,7 +698,7 @@ class CuraApplication(QtApplication):
|
||||
self._message_box_callback_arguments = []
|
||||
|
||||
# Cura has multiple locations where instance containers need to be saved, so we need to handle this differently.
|
||||
def saveSettings(self):
|
||||
def saveSettings(self) -> None:
|
||||
if not self.started:
|
||||
# Do not do saving during application start or when data should not be saved on quit.
|
||||
return
|
||||
@ -989,8 +988,8 @@ class CuraApplication(QtApplication):
|
||||
## Get the machine action manager
|
||||
# We ignore any *args given to this, as we also register the machine manager as qml singleton.
|
||||
# It wants to give this function an engine and script engine, but we don't care about that.
|
||||
def getMachineActionManager(self, *args):
|
||||
return self._machine_action_manager
|
||||
def getMachineActionManager(self, *args: Any) -> MachineActionManager.MachineActionManager:
|
||||
return cast(MachineActionManager.MachineActionManager, self._machine_action_manager)
|
||||
|
||||
@pyqtSlot(result = QObject)
|
||||
def getMaterialManagementModel(self) -> MaterialManagementModel:
|
||||
@ -1443,7 +1442,7 @@ class CuraApplication(QtApplication):
|
||||
if center is not None:
|
||||
object_centers.append(center)
|
||||
|
||||
if object_centers and len(object_centers) > 0:
|
||||
if object_centers:
|
||||
middle_x = sum([v.x for v in object_centers]) / len(object_centers)
|
||||
middle_y = sum([v.y for v in object_centers]) / len(object_centers)
|
||||
middle_z = sum([v.z for v in object_centers]) / len(object_centers)
|
||||
@ -1493,7 +1492,7 @@ class CuraApplication(QtApplication):
|
||||
if center is not None:
|
||||
object_centers.append(center)
|
||||
|
||||
if object_centers and len(object_centers) > 0:
|
||||
if object_centers:
|
||||
middle_x = sum([v.x for v in object_centers]) / len(object_centers)
|
||||
middle_y = sum([v.y for v in object_centers]) / len(object_centers)
|
||||
middle_z = sum([v.z for v in object_centers]) / len(object_centers)
|
||||
@ -1675,7 +1674,7 @@ class CuraApplication(QtApplication):
|
||||
extension = os.path.splitext(f)[1]
|
||||
extension = extension.lower()
|
||||
filename = os.path.basename(f)
|
||||
if len(self._currently_loading_files) > 0:
|
||||
if self._currently_loading_files:
|
||||
# If a non-slicable file is already being loaded, we prevent loading of any further non-slicable files
|
||||
if extension in self._non_sliceable_extensions:
|
||||
message = Message(
|
||||
@ -1796,8 +1795,8 @@ class CuraApplication(QtApplication):
|
||||
node.addDecorator(build_plate_decorator)
|
||||
build_plate_decorator.setBuildPlateNumber(target_build_plate)
|
||||
|
||||
op = AddSceneNodeOperation(node, scene.getRoot())
|
||||
op.push()
|
||||
operation = AddSceneNodeOperation(node, scene.getRoot())
|
||||
operation.push()
|
||||
|
||||
node.callDecoration("setActiveExtruder", default_extruder_id)
|
||||
scene.sceneChanged.emit(node)
|
||||
@ -1871,16 +1870,14 @@ class CuraApplication(QtApplication):
|
||||
main_window = QtApplication.getInstance().getMainWindow()
|
||||
if main_window:
|
||||
return main_window.width()
|
||||
else:
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@pyqtSlot(result = int)
|
||||
def appHeight(self) -> int:
|
||||
main_window = QtApplication.getInstance().getMainWindow()
|
||||
if main_window:
|
||||
return main_window.height()
|
||||
else:
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@pyqtSlot()
|
||||
def deleteAll(self, only_selectable: bool = True) -> None:
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from typing import List, Tuple
|
||||
from typing import List, Tuple, TYPE_CHECKING, Optional
|
||||
|
||||
from cura.CuraApplication import CuraApplication #To find some resource types.
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
@ -9,12 +9,16 @@ from cura.Settings.GlobalStack import GlobalStack
|
||||
from UM.PackageManager import PackageManager #The class we're extending.
|
||||
from UM.Resources import Resources #To find storage paths for some resource types.
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.Qt.QtApplication import QtApplication
|
||||
from PyQt5.QtCore import QObject
|
||||
|
||||
|
||||
class CuraPackageManager(PackageManager):
|
||||
def __init__(self, application, parent = None):
|
||||
def __init__(self, application: "QtApplication", parent: Optional["QObject"] = None):
|
||||
super().__init__(application, parent)
|
||||
|
||||
def initialize(self):
|
||||
def initialize(self) -> None:
|
||||
self._installation_dirs_dict["materials"] = Resources.getStoragePath(CuraApplication.ResourceTypes.MaterialInstanceContainer)
|
||||
self._installation_dirs_dict["qualities"] = Resources.getStoragePath(CuraApplication.ResourceTypes.QualityInstanceContainer)
|
||||
|
||||
|
@ -26,6 +26,7 @@ class CuraView(View):
|
||||
def mainComponent(self) -> QUrl:
|
||||
return self.getDisplayComponent("main")
|
||||
|
||||
|
||||
@pyqtProperty(QUrl, constant = True)
|
||||
def stageMenuComponent(self) -> QUrl:
|
||||
url = self.getDisplayComponent("menu")
|
||||
|
@ -33,10 +33,10 @@ class Layer:
|
||||
def elementCount(self):
|
||||
return self._element_count
|
||||
|
||||
def setHeight(self, height):
|
||||
def setHeight(self, height: float) -> None:
|
||||
self._height = height
|
||||
|
||||
def setThickness(self, thickness):
|
||||
def setThickness(self, thickness: float) -> None:
|
||||
self._thickness = thickness
|
||||
|
||||
def lineMeshVertexCount(self) -> int:
|
||||
|
@ -16,8 +16,7 @@ class LayerData(MeshData):
|
||||
def getLayer(self, layer):
|
||||
if layer in self._layers:
|
||||
return self._layers[layer]
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
def getLayers(self):
|
||||
return self._layers
|
||||
|
@ -9,7 +9,7 @@ from cura.LayerData import LayerData
|
||||
|
||||
## Simple decorator to indicate a scene node holds layer data.
|
||||
class LayerDataDecorator(SceneNodeDecorator):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._layer_data = None # type: Optional[LayerData]
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from UM.Qt.QtApplication import QtApplication
|
||||
from typing import Any, Optional
|
||||
import numpy
|
||||
|
||||
from typing import Optional, cast
|
||||
|
||||
from UM.Qt.Bindings.Theme import Theme
|
||||
from UM.Qt.QtApplication import QtApplication
|
||||
from UM.Logger import Logger
|
||||
|
||||
|
||||
@ -61,7 +62,7 @@ class LayerPolygon:
|
||||
|
||||
# When type is used as index returns true if type == LayerPolygon.InfillType or type == LayerPolygon.SkinType or type == LayerPolygon.SupportInfillType
|
||||
# Should be generated in better way, not hardcoded.
|
||||
self._isInfillOrSkinTypeMap = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0], dtype = numpy.bool)
|
||||
self._is_infill_or_skin_type_map = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0], dtype = numpy.bool)
|
||||
|
||||
self._build_cache_line_mesh_mask = None # type: Optional[numpy.ndarray]
|
||||
self._build_cache_needed_points = None # type: Optional[numpy.ndarray]
|
||||
@ -149,17 +150,17 @@ class LayerPolygon:
|
||||
def getColors(self):
|
||||
return self._colors
|
||||
|
||||
def mapLineTypeToColor(self, line_types):
|
||||
def mapLineTypeToColor(self, line_types: numpy.ndarray) -> numpy.ndarray:
|
||||
return self._color_map[line_types]
|
||||
|
||||
def isInfillOrSkinType(self, line_types):
|
||||
return self._isInfillOrSkinTypeMap[line_types]
|
||||
def isInfillOrSkinType(self, line_types: numpy.ndarray) -> numpy.ndarray:
|
||||
return self._is_infill_or_skin_type_map[line_types]
|
||||
|
||||
def lineMeshVertexCount(self):
|
||||
return (self._vertex_end - self._vertex_begin)
|
||||
def lineMeshVertexCount(self) -> int:
|
||||
return self._vertex_end - self._vertex_begin
|
||||
|
||||
def lineMeshElementCount(self):
|
||||
return (self._index_end - self._index_begin)
|
||||
def lineMeshElementCount(self) -> int:
|
||||
return self._index_end - self._index_begin
|
||||
|
||||
@property
|
||||
def extruder(self):
|
||||
@ -202,7 +203,7 @@ class LayerPolygon:
|
||||
return self._jump_count
|
||||
|
||||
# Calculate normals for the entire polygon using numpy.
|
||||
def getNormals(self):
|
||||
def getNormals(self) -> numpy.ndarray:
|
||||
normals = numpy.copy(self._data)
|
||||
normals[:, 1] = 0.0 # We are only interested in 2D normals
|
||||
|
||||
@ -226,13 +227,13 @@ class LayerPolygon:
|
||||
|
||||
return normals
|
||||
|
||||
__color_map = None # type: numpy.ndarray[Any]
|
||||
__color_map = None # type: numpy.ndarray
|
||||
|
||||
## Gets the instance of the VersionUpgradeManager, or creates one.
|
||||
@classmethod
|
||||
def getColorMap(cls):
|
||||
def getColorMap(cls) -> numpy.ndarray:
|
||||
if cls.__color_map is None:
|
||||
theme = QtApplication.getInstance().getTheme()
|
||||
theme = cast(Theme, QtApplication.getInstance().getTheme())
|
||||
cls.__color_map = numpy.array([
|
||||
theme.getColor("layerview_none").getRgbF(), # NoneType
|
||||
theme.getColor("layerview_inset_0").getRgbF(), # Inset0Type
|
||||
|
@ -26,7 +26,7 @@ class ContainerNode:
|
||||
## Gets the metadata of the container that this node represents.
|
||||
# Getting the metadata from the container directly is about 10x as fast.
|
||||
# \return The metadata of the container in this node.
|
||||
def getMetadata(self):
|
||||
def getMetadata(self) -> Dict[str, Any]:
|
||||
return ContainerRegistry.getInstance().findContainersMetadata(id = self.container_id)[0]
|
||||
|
||||
## Get an entry from the metadata of the container that this node contains.
|
||||
|
@ -30,7 +30,7 @@ if TYPE_CHECKING:
|
||||
# nodes that have children) but that child node may be a node representing the
|
||||
# empty instance container.
|
||||
class ContainerTree:
|
||||
__instance = None
|
||||
__instance = None # type: Optional["ContainerTree"]
|
||||
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
@ -75,7 +75,7 @@ class ContainerTree:
|
||||
return self.machines[global_stack.definition.getId()].getQualityChangesGroups(variant_names, material_bases, extruder_enabled)
|
||||
|
||||
## Ran after completely starting up the application.
|
||||
def _onStartupFinished(self):
|
||||
def _onStartupFinished(self) -> None:
|
||||
currently_added = ContainerRegistry.getInstance().findContainerStacks() # Find all currently added global stacks.
|
||||
JobQueue.getInstance().add(self._MachineNodeLoadJob(self, currently_added))
|
||||
|
||||
@ -137,7 +137,7 @@ class ContainerTree:
|
||||
# \param container_stacks All of the stacks to pre-load the container
|
||||
# trees for. This needs to be provided from here because the stacks
|
||||
# need to be constructed on the main thread because they are QObject.
|
||||
def __init__(self, tree_root: "ContainerTree", container_stacks: List["ContainerStack"]):
|
||||
def __init__(self, tree_root: "ContainerTree", container_stacks: List["ContainerStack"]) -> None:
|
||||
self.tree_root = tree_root
|
||||
self.container_stacks = container_stacks
|
||||
super().__init__()
|
||||
|
@ -6,13 +6,13 @@ import time
|
||||
from collections import deque
|
||||
|
||||
from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtProperty
|
||||
from typing import Optional, Any, Set
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
from UM.Settings.SettingDefinition import SettingDefinition
|
||||
from UM.Settings.Validator import ValidatorState
|
||||
|
||||
|
||||
import cura.CuraApplication
|
||||
#
|
||||
# This class performs setting error checks for the currently active machine.
|
||||
#
|
||||
@ -24,25 +24,25 @@ from UM.Settings.Validator import ValidatorState
|
||||
#
|
||||
class MachineErrorChecker(QObject):
|
||||
|
||||
def __init__(self, parent = None):
|
||||
def __init__(self, parent: Optional[QObject] = None) -> None:
|
||||
super().__init__(parent)
|
||||
|
||||
self._global_stack = None
|
||||
|
||||
self._has_errors = True # Result of the error check, indicating whether there are errors in the stack
|
||||
self._error_keys = set() # A set of settings keys that have errors
|
||||
self._error_keys_in_progress = set() # The variable that stores the results of the currently in progress check
|
||||
self._error_keys = set() # type: Set[str] # A set of settings keys that have errors
|
||||
self._error_keys_in_progress = set() # type: Set[str] # The variable that stores the results of the currently in progress check
|
||||
|
||||
self._stacks_and_keys_to_check = None # a FIFO queue of tuples (stack, key) to check for errors
|
||||
self._stacks_and_keys_to_check = None # type: Optional[deque] # a FIFO queue of tuples (stack, key) to check for errors
|
||||
|
||||
self._need_to_check = False # Whether we need to schedule a new check or not. This flag is set when a new
|
||||
# error check needs to take place while there is already one running at the moment.
|
||||
self._check_in_progress = False # Whether there is an error check running in progress at the moment.
|
||||
|
||||
self._application = Application.getInstance()
|
||||
self._application = cura.CuraApplication.CuraApplication.getInstance()
|
||||
self._machine_manager = self._application.getMachineManager()
|
||||
|
||||
self._start_time = 0 # measure checking time
|
||||
self._start_time = 0. # measure checking time
|
||||
|
||||
# This timer delays the starting of error check so we can react less frequently if the user is frequently
|
||||
# changing settings.
|
||||
@ -94,13 +94,13 @@ class MachineErrorChecker(QObject):
|
||||
|
||||
# Start the error check for property changed
|
||||
# this is seperate from the startErrorCheck because it ignores a number property types
|
||||
def startErrorCheckPropertyChanged(self, key, property_name):
|
||||
def startErrorCheckPropertyChanged(self, key: str, property_name: str) -> None:
|
||||
if property_name != "value":
|
||||
return
|
||||
self.startErrorCheck()
|
||||
|
||||
# Starts the error check timer to schedule a new error check.
|
||||
def startErrorCheck(self, *args) -> None:
|
||||
def startErrorCheck(self, *args: Any) -> None:
|
||||
if not self._check_in_progress:
|
||||
self._need_to_check = True
|
||||
self.needToWaitForResultChanged.emit()
|
||||
|
@ -176,9 +176,9 @@ class MachineNode(ContainerNode):
|
||||
|
||||
# Find the global qualities for this printer.
|
||||
global_qualities = container_registry.findInstanceContainersMetadata(type = "quality", definition = self.quality_definition, global_quality = "True") # First try specific to this printer.
|
||||
if len(global_qualities) == 0: # This printer doesn't override the global qualities.
|
||||
if not global_qualities: # This printer doesn't override the global qualities.
|
||||
global_qualities = container_registry.findInstanceContainersMetadata(type = "quality", definition = "fdmprinter", global_quality = "True") # Otherwise pick the global global qualities.
|
||||
if len(global_qualities) == 0: # There are no global qualities either?! Something went very wrong, but we'll not crash and properly fill the tree.
|
||||
if not global_qualities: # There are no global qualities either?! Something went very wrong, but we'll not crash and properly fill the tree.
|
||||
global_qualities = [cura.CuraApplication.CuraApplication.getInstance().empty_quality_container.getMetaData()]
|
||||
for global_quality in global_qualities:
|
||||
self.global_qualities[global_quality["quality_type"]] = QualityNode(global_quality["id"], parent = self)
|
||||
|
@ -14,6 +14,7 @@ if TYPE_CHECKING:
|
||||
from typing import Dict
|
||||
from cura.Machines.VariantNode import VariantNode
|
||||
|
||||
|
||||
## Represents a material in the container tree.
|
||||
#
|
||||
# Its subcontainers are quality profiles.
|
||||
|
@ -41,4 +41,4 @@ class QualityNode(ContainerNode):
|
||||
self.intents[intent["id"]] = IntentNode(intent["id"], quality = self)
|
||||
|
||||
self.intents["empty_intent"] = IntentNode("empty_intent", quality = self)
|
||||
# Otherwise, there are no intents for global profiles.
|
||||
# Otherwise, there are no intents for global profiles.
|
||||
|
@ -47,7 +47,7 @@ class MultiplyObjectsJob(Job):
|
||||
nodes = []
|
||||
|
||||
not_fit_count = 0
|
||||
|
||||
found_solution_for_all = False
|
||||
for node in self._objects:
|
||||
# If object is part of a group, multiply group
|
||||
current_node = node
|
||||
@ -66,7 +66,7 @@ class MultiplyObjectsJob(Job):
|
||||
|
||||
found_solution_for_all = True
|
||||
arranger.resetLastPriority()
|
||||
for i in range(self._count):
|
||||
for _ in range(self._count):
|
||||
# We do place the nodes one by one, as we want to yield in between.
|
||||
new_node = copy.deepcopy(node)
|
||||
solution_found = False
|
||||
@ -98,10 +98,10 @@ class MultiplyObjectsJob(Job):
|
||||
Job.yieldThread()
|
||||
|
||||
if nodes:
|
||||
op = GroupedOperation()
|
||||
operation = GroupedOperation()
|
||||
for new_node in nodes:
|
||||
op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
|
||||
op.push()
|
||||
operation.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
|
||||
operation.push()
|
||||
status_message.hide()
|
||||
|
||||
if not found_solution_for_all:
|
||||
|
@ -1,10 +1,10 @@
|
||||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
from typing import Optional
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
|
||||
class BaseModel:
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
self.__dict__.update(kwargs)
|
||||
|
||||
|
||||
@ -53,9 +53,10 @@ class ResponseData(BaseModel):
|
||||
redirect_uri = None # type: Optional[str]
|
||||
content_type = "text/html" # type: str
|
||||
|
||||
|
||||
## Possible HTTP responses.
|
||||
HTTP_STATUS = {
|
||||
"OK": ResponseStatus(code = 200, message = "OK"),
|
||||
"NOT_FOUND": ResponseStatus(code = 404, message = "NOT FOUND"),
|
||||
"REDIRECT": ResponseStatus(code = 302, message = "REDIRECT")
|
||||
}
|
||||
} # type: Dict[str, ResponseStatus]
|
||||
|
@ -1,26 +1,27 @@
|
||||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Operations.Operation import Operation
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
|
||||
|
||||
## A specialised operation designed specifically to modify the previous operation.
|
||||
class PlatformPhysicsOperation(Operation):
|
||||
def __init__(self, node, translation):
|
||||
def __init__(self, node: SceneNode, translation: Vector):
|
||||
super().__init__()
|
||||
self._node = node
|
||||
self._old_transformation = node.getLocalTransformation()
|
||||
self._translation = translation
|
||||
self._always_merge = True
|
||||
|
||||
def undo(self):
|
||||
def undo(self) -> None:
|
||||
self._node.setTransformation(self._old_transformation)
|
||||
|
||||
def redo(self):
|
||||
def redo(self) -> None:
|
||||
self._node.translate(self._translation, SceneNode.TransformSpace.World)
|
||||
|
||||
def mergeWith(self, other):
|
||||
def mergeWith(self, other: Operation) -> GroupedOperation:
|
||||
group = GroupedOperation()
|
||||
|
||||
group.addOperation(other)
|
||||
@ -28,5 +29,5 @@ class PlatformPhysicsOperation(Operation):
|
||||
|
||||
return group
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return "PlatformPhysicsOp.(trans.={0})".format(self._translation)
|
||||
|
@ -6,9 +6,9 @@ from UM.Operations.Operation import Operation
|
||||
|
||||
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
||||
|
||||
|
||||
## Simple operation to set the buildplate number of a scenenode.
|
||||
class SetBuildPlateNumberOperation(Operation):
|
||||
|
||||
def __init__(self, node: SceneNode, build_plate_nr: int) -> None:
|
||||
super().__init__()
|
||||
self._node = node
|
||||
@ -16,11 +16,11 @@ class SetBuildPlateNumberOperation(Operation):
|
||||
self._previous_build_plate_nr = None
|
||||
self._decorator_added = False
|
||||
|
||||
def undo(self):
|
||||
def undo(self) -> None:
|
||||
if self._previous_build_plate_nr:
|
||||
self._node.callDecoration("setBuildPlateNumber", self._previous_build_plate_nr)
|
||||
|
||||
def redo(self):
|
||||
def redo(self) -> None:
|
||||
stack = self._node.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway.
|
||||
if not stack:
|
||||
self._node.addDecorator(SettingOverrideDecorator())
|
||||
|
@ -1,36 +1,37 @@
|
||||
# Copyright (c) 2016 Ultimaker B.V.
|
||||
# Uranium is released under the terms of the LGPLv3 or higher.
|
||||
from typing import Optional
|
||||
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Operations import Operation
|
||||
|
||||
from UM.Math.Vector import Vector
|
||||
|
||||
## An operation that parents a scene node to another scene node.
|
||||
|
||||
## An operation that parents a scene node to another scene node.
|
||||
class SetParentOperation(Operation.Operation):
|
||||
## Initialises this SetParentOperation.
|
||||
#
|
||||
# \param node The node which will be reparented.
|
||||
# \param parent_node The node which will be the parent.
|
||||
def __init__(self, node, parent_node):
|
||||
def __init__(self, node: SceneNode, parent_node: Optional[SceneNode]):
|
||||
super().__init__()
|
||||
self._node = node
|
||||
self._parent = parent_node
|
||||
self._old_parent = node.getParent() # To restore the previous parent in case of an undo.
|
||||
|
||||
## Undoes the set-parent operation, restoring the old parent.
|
||||
def undo(self):
|
||||
def undo(self) -> None:
|
||||
self._set_parent(self._old_parent)
|
||||
|
||||
## Re-applies the set-parent operation.
|
||||
def redo(self):
|
||||
def redo(self) -> None:
|
||||
self._set_parent(self._parent)
|
||||
|
||||
## Sets the parent of the node while applying transformations to the world-transform of the node stays the same.
|
||||
#
|
||||
# \param new_parent The new parent. Note: this argument can be None, which would hide the node from the scene.
|
||||
def _set_parent(self, new_parent):
|
||||
def _set_parent(self, new_parent: Optional[SceneNode]) -> None:
|
||||
if new_parent:
|
||||
current_parent = self._node.getParent()
|
||||
if current_parent:
|
||||
@ -59,5 +60,5 @@ class SetParentOperation(Operation.Operation):
|
||||
## Returns a programmer-readable representation of this operation.
|
||||
#
|
||||
# \return A programmer-readable representation of this operation.
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return "SetParentOperation(node = {0}, parent_node={1})".format(self._node, self._parent)
|
||||
|
@ -17,9 +17,6 @@ from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.View.GL.ShaderProgram import ShaderProgram
|
||||
|
||||
MYPY = False
|
||||
if MYPY:
|
||||
from UM.Scene.Camera import Camera
|
||||
|
||||
|
||||
|
@ -3,6 +3,7 @@ from PyQt5.QtQuick import QQuickImageProvider
|
||||
from PyQt5.QtCore import QSize
|
||||
|
||||
from UM.Application import Application
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
class PrintJobPreviewImageProvider(QQuickImageProvider):
|
||||
@ -10,7 +11,7 @@ class PrintJobPreviewImageProvider(QQuickImageProvider):
|
||||
super().__init__(QQuickImageProvider.Image)
|
||||
|
||||
## Request a new image.
|
||||
def requestImage(self, id: str, size: QSize) -> QImage:
|
||||
def requestImage(self, id: str, size: QSize) -> Tuple[QImage, QSize]:
|
||||
# The id will have an uuid and an increment separated by a slash. As we don't care about the value of the
|
||||
# increment, we need to strip that first.
|
||||
uuid = id[id.find("/") + 1:]
|
||||
@ -22,6 +23,6 @@ class PrintJobPreviewImageProvider(QQuickImageProvider):
|
||||
if print_job.key == uuid:
|
||||
if print_job.getPreviewImage():
|
||||
return print_job.getPreviewImage(), QSize(15, 15)
|
||||
else:
|
||||
return QImage(), QSize(15, 15)
|
||||
return QImage(), QSize(15,15)
|
||||
|
||||
return QImage(), QSize(15, 15)
|
||||
return QImage(), QSize(15, 15)
|
@ -161,7 +161,7 @@ class PrintJobOutputModel(QObject):
|
||||
self._time_elapsed = new_time_elapsed
|
||||
self.timeElapsedChanged.emit()
|
||||
|
||||
def updateState(self, new_state):
|
||||
def updateState(self, new_state: str) -> None:
|
||||
if self._state != new_state:
|
||||
self._state = new_state
|
||||
self.stateChanged.emit()
|
||||
|
@ -148,7 +148,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
|
||||
|
||||
@pyqtProperty(QObject, notify = printersChanged)
|
||||
def activePrinter(self) -> Optional["PrinterOutputModel"]:
|
||||
if len(self._printers):
|
||||
if self._printers:
|
||||
return self._printers[0]
|
||||
return None
|
||||
|
||||
|
@ -10,3 +10,6 @@ class BlockSlicingDecorator(SceneNodeDecorator):
|
||||
|
||||
def isBlockSlicing(self) -> bool:
|
||||
return True
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return BlockSlicingDecorator()
|
@ -17,8 +17,8 @@ class GCodeListDecorator(SceneNodeDecorator):
|
||||
def getGCodeList(self) -> List[str]:
|
||||
return self._gcode_list
|
||||
|
||||
def setGCodeList(self, list: List[str]) -> None:
|
||||
self._gcode_list = list
|
||||
def setGCodeList(self, gcode_list: List[str]) -> None:
|
||||
self._gcode_list = gcode_list
|
||||
|
||||
def __deepcopy__(self, memo) -> "GCodeListDecorator":
|
||||
copied_decorator = GCodeListDecorator()
|
||||
|
@ -15,7 +15,6 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.SettingInstance import SettingInstance
|
||||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
from UM.Platform import Platform
|
||||
@ -176,7 +175,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||
if not file_name:
|
||||
return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename>!", "Failed to import profile from <filename>{0}</filename>: {1}", file_name, "Invalid path")}
|
||||
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
||||
if not global_stack:
|
||||
return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename>!", "Can't import profile from <filename>{0}</filename> before a printer is added.", file_name)}
|
||||
container_tree = ContainerTree.getInstance()
|
||||
@ -384,7 +383,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||
if not quality_type:
|
||||
return catalog.i18nc("@info:status", "Profile is missing a quality type.")
|
||||
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
||||
if global_stack is None:
|
||||
return None
|
||||
definition_id = ContainerTree.getInstance().machines[global_stack.definition.getId()].quality_definition
|
||||
|
@ -43,7 +43,7 @@ class MachineActionManager(QObject):
|
||||
# Dict of all actions that need to be done when first added by definition ID
|
||||
self._first_start_actions = {} # type: Dict[str, List[MachineAction]]
|
||||
|
||||
def initialize(self):
|
||||
def initialize(self) -> None:
|
||||
# Add machine_action as plugin type
|
||||
PluginRegistry.addType("machine_action", self.addMachineAction)
|
||||
|
||||
|
@ -48,6 +48,7 @@ UM.Dialog{
|
||||
{
|
||||
font: UM.Theme.getFont("default")
|
||||
text: catalog.i18nc("@label", "The following packages will be added:")
|
||||
visible: toolbox.has_compatible_packages
|
||||
color: UM.Theme.getColor("text")
|
||||
height: contentHeight + UM.Theme.getSize("default_margin").height
|
||||
}
|
||||
@ -59,8 +60,8 @@ UM.Dialog{
|
||||
Item
|
||||
{
|
||||
width: parent.width
|
||||
property var lineHeight: 60
|
||||
visible: model.is_compatible == "True" ? true : false
|
||||
property int lineHeight: 60
|
||||
visible: model.is_compatible
|
||||
height: visible ? (lineHeight + UM.Theme.getSize("default_margin").height) : 0 // We only show the compatible packages here
|
||||
Image
|
||||
{
|
||||
@ -90,6 +91,7 @@ UM.Dialog{
|
||||
{
|
||||
font: UM.Theme.getFont("default")
|
||||
text: catalog.i18nc("@label", "The following packages can not be installed because of incompatible Cura version:")
|
||||
visible: toolbox.has_incompatible_packages
|
||||
color: UM.Theme.getColor("text")
|
||||
height: contentHeight + UM.Theme.getSize("default_margin").height
|
||||
}
|
||||
@ -101,8 +103,8 @@ UM.Dialog{
|
||||
Item
|
||||
{
|
||||
width: parent.width
|
||||
property var lineHeight: 60
|
||||
visible: model.is_compatible == "True" ? false : true
|
||||
property int lineHeight: 60
|
||||
visible: !model.is_compatible
|
||||
height: visible ? (lineHeight + UM.Theme.getSize("default_margin").height) : 0 // We only show the incompatible packages here
|
||||
Image
|
||||
{
|
||||
|
@ -57,6 +57,7 @@ UM.Dialog
|
||||
{
|
||||
licenseDialog.close();
|
||||
toolbox.install(licenseDialog.pluginFileLocation);
|
||||
toolbox.subscribe(licenseDialog.pluginName);
|
||||
}
|
||||
},
|
||||
Button
|
||||
|
@ -10,6 +10,7 @@ class SubscribedPackagesModel(ListModel):
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(parent)
|
||||
|
||||
self._items = []
|
||||
self._metadata = None
|
||||
self._discrepancies = None
|
||||
self._sdk_version = ApplicationMetadata.CuraSDKVersion
|
||||
@ -27,20 +28,34 @@ class SubscribedPackagesModel(ListModel):
|
||||
self._discrepancies = discrepancy
|
||||
|
||||
def update(self):
|
||||
items = []
|
||||
self._items.clear()
|
||||
|
||||
for item in self._metadata:
|
||||
if item["package_id"] not in self._discrepancies:
|
||||
continue
|
||||
package = {"name": item["display_name"], "sdk_versions": item["sdk_versions"]}
|
||||
if self._sdk_version not in item["sdk_versions"]:
|
||||
package.update({"is_compatible": "False"})
|
||||
package.update({"is_compatible": False})
|
||||
else:
|
||||
package.update({"is_compatible": "True"})
|
||||
package.update({"is_compatible": True})
|
||||
try:
|
||||
package.update({"icon_url": item["icon_url"]})
|
||||
except KeyError: # There is no 'icon_url" in the response payload for this package
|
||||
package.update({"icon_url": ""})
|
||||
|
||||
items.append(package)
|
||||
self.setItems(items)
|
||||
self._items.append(package)
|
||||
self.setItems(self._items)
|
||||
|
||||
def hasCompatiblePackages(self) -> bool:
|
||||
has_compatible_items = False
|
||||
for item in self._items:
|
||||
if item['is_compatible'] == True:
|
||||
has_compatible_items = True
|
||||
return has_compatible_items
|
||||
|
||||
def hasIncompatiblePackages(self) -> bool:
|
||||
has_incompatible_items = False
|
||||
for item in self._items:
|
||||
if item['is_compatible'] == False:
|
||||
has_incompatible_items = True
|
||||
return has_incompatible_items
|
@ -164,6 +164,14 @@ class Toolbox(QObject, Extension):
|
||||
|
||||
self._application.getHttpRequestManager().put(url, headers_dict = self._request_headers,
|
||||
data = data.encode())
|
||||
@pyqtSlot(str)
|
||||
def subscribe(self, package_id: str) -> None:
|
||||
if self._application.getCuraAPI().account.isLoggedIn:
|
||||
data = "{\"data\": {\"package_id\": \"%s\", \"sdk_version\": \"%s\"}}" % (package_id, self._sdk_version)
|
||||
self._application.getHttpRequestManager().put(url=self._api_url_user_packages,
|
||||
headers_dict=self._request_headers,
|
||||
data=data.encode()
|
||||
)
|
||||
|
||||
@pyqtSlot(result = str)
|
||||
def getLicenseDialogPluginName(self) -> str:
|
||||
@ -221,12 +229,6 @@ class Toolbox(QObject, Extension):
|
||||
self._makeRequestByType("updates")
|
||||
self._fetchUserSubscribedPackages()
|
||||
|
||||
@pyqtSlot()
|
||||
def browsePackages(self) -> None:
|
||||
# Make remote requests:
|
||||
self._fetchPackageData()
|
||||
# Gather installed packages:
|
||||
self._updateInstalledModels()
|
||||
|
||||
def _fetchUserSubscribedPackages(self):
|
||||
if self._application.getCuraAPI().account.isLoggedIn:
|
||||
@ -235,6 +237,7 @@ class Toolbox(QObject, Extension):
|
||||
def _fetchPackageData(self) -> None:
|
||||
self._makeRequestByType("packages")
|
||||
self._makeRequestByType("authors")
|
||||
self._updateInstalledModels()
|
||||
|
||||
# Displays the toolbox
|
||||
@pyqtSlot()
|
||||
@ -733,6 +736,7 @@ class Toolbox(QObject, Extension):
|
||||
return
|
||||
|
||||
self.install(file_path)
|
||||
self.subscribe(package_info["package_id"])
|
||||
|
||||
# Getter & Setters for Properties:
|
||||
# --------------------------------------------------------------------------
|
||||
@ -792,6 +796,14 @@ class Toolbox(QObject, Extension):
|
||||
def subscribedPackagesModel(self) -> SubscribedPackagesModel:
|
||||
return cast(SubscribedPackagesModel, self._models["subscribed_packages"])
|
||||
|
||||
@pyqtProperty(bool, constant=True)
|
||||
def has_compatible_packages(self) -> bool:
|
||||
return self._models["subscribed_packages"].hasCompatiblePackages()
|
||||
|
||||
@pyqtProperty(bool, constant=True)
|
||||
def has_incompatible_packages(self) -> bool:
|
||||
return self._models["subscribed_packages"].hasIncompatiblePackages()
|
||||
|
||||
@pyqtProperty(QObject, constant = True)
|
||||
def packagesModel(self) -> PackagesModel:
|
||||
return cast(PackagesModel, self._models["packages"])
|
||||
|
@ -258,7 +258,7 @@
|
||||
"support_interface_density": { "value": 33.333 },
|
||||
"support_interface_pattern": { "value": "'grid'" },
|
||||
"support_interface_skip_height": { "value": 0.2 },
|
||||
"minimum_support_area": { "value": 5 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"top_bottom_thickness": {"value": "layer_height_0 + layer_height * 3" },
|
||||
"wall_thickness": {"value": "line_width * 2" }
|
||||
|
@ -4521,6 +4521,7 @@
|
||||
"type": "float",
|
||||
"default_value": 0.0,
|
||||
"minimum_value": "0",
|
||||
"maximum_value_warning": "5",
|
||||
"enabled": "support_enable",
|
||||
"limit_to_extruder": "support_infill_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
@ -7416,7 +7417,7 @@
|
||||
"clean_between_layers":
|
||||
{
|
||||
"label": "Wipe Nozzle Between Layers",
|
||||
"description": "Whether to include nozzle wipe G-Code between layers. Enabling this setting could influence behavior of retract at layer change. Please use Wipe Retraction settings to control retraction at layers where the wipe script will be working.",
|
||||
"description": "Whether to include nozzle wipe G-Code between layers (maximum 1 per layer). Enabling this setting could influence behavior of retract at layer change. Please use Wipe Retraction settings to control retraction at layers where the wipe script will be working.",
|
||||
"default_value": false,
|
||||
"type": "bool",
|
||||
"settable_per_mesh": false,
|
||||
@ -7426,7 +7427,7 @@
|
||||
"max_extrusion_before_wipe":
|
||||
{
|
||||
"label": "Material Volume Between Wipes",
|
||||
"description": "Maximum material, that can be extruded before another nozzle wipe is initiated.",
|
||||
"description": "Maximum material that can be extruded before another nozzle wipe is initiated. If this value is less than the volume of material required in a layer, the setting has no effect in this layer, i.e. it is limited to one wipe per layer.",
|
||||
"default_value": 10,
|
||||
"type": "float",
|
||||
"unit": "mm³",
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2019 Ultimaker B.V.
|
||||
// Copyright (c) 2020 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
@ -21,7 +21,16 @@ UM.MainWindow
|
||||
id: base
|
||||
|
||||
// Cura application window title
|
||||
title: PrintInformation.jobName + " - " + catalog.i18nc("@title:window", CuraApplication.applicationDisplayName)
|
||||
title:
|
||||
{
|
||||
let result = "";
|
||||
if(PrintInformation.jobName != "")
|
||||
{
|
||||
result += PrintInformation.jobName + " - ";
|
||||
}
|
||||
result += CuraApplication.applicationDisplayName;
|
||||
return result;
|
||||
}
|
||||
|
||||
backgroundColor: UM.Theme.getColor("viewport_background")
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user