mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-10 08:17:49 -06:00
Merge remote-tracking branch 'origin/master' into CURA-6983_sync_packages
# Conflicts: # plugins/Toolbox/src/CloudSync/SubscribedPackagesModel.py # plugins/Toolbox/src/Toolbox.py
This commit is contained in:
commit
182bab6467
44 changed files with 343 additions and 161 deletions
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.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# 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.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
@ -8,6 +8,7 @@ from UM.Math.Polygon import Polygon
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from cura.Arranging.ShapeArray import ShapeArray
|
from cura.Arranging.ShapeArray import ShapeArray
|
||||||
|
from cura.BuildVolume import BuildVolume
|
||||||
from cura.Scene import ZOffsetDecorator
|
from cura.Scene import ZOffsetDecorator
|
||||||
|
|
||||||
from collections import namedtuple
|
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.
|
# Note: Make sure the scale is the same between ShapeArray objects and the Arrange instance.
|
||||||
class Arrange:
|
class Arrange:
|
||||||
build_volume = None
|
build_volume = None # type: Optional[BuildVolume]
|
||||||
|
|
||||||
def __init__(self, x, y, offset_x, offset_y, scale= 0.5):
|
def __init__(self, x, y, offset_x, offset_y, scale= 0.5):
|
||||||
self._scale = scale # convert input coordinates to arrange coordinates
|
self._scale = scale # convert input coordinates to arrange coordinates
|
||||||
|
@ -68,7 +69,7 @@ class Arrange:
|
||||||
points = copy.deepcopy(vertices._points)
|
points = copy.deepcopy(vertices._points)
|
||||||
|
|
||||||
# After scaling (like up to 0.1 mm) the node might not have points
|
# After scaling (like up to 0.1 mm) the node might not have points
|
||||||
if len(points) == 0:
|
if not points.size:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
||||||
|
@ -113,7 +114,7 @@ class Arrange:
|
||||||
found_spot = True
|
found_spot = True
|
||||||
self.place(x, y, offset_shape_arr) # place the object in arranger
|
self.place(x, y, offset_shape_arr) # place the object in arranger
|
||||||
else:
|
else:
|
||||||
Logger.log("d", "Could not find spot!"),
|
Logger.log("d", "Could not find spot!")
|
||||||
found_spot = False
|
found_spot = False
|
||||||
node.setPosition(Vector(200, center_y, 100))
|
node.setPosition(Vector(200, center_y, 100))
|
||||||
return found_spot
|
return found_spot
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ArrangeArray:
|
||||||
self._has_empty = False
|
self._has_empty = False
|
||||||
self._arrange = [] # type: List[Arrange]
|
self._arrange = [] # type: List[Arrange]
|
||||||
|
|
||||||
def _update_first_empty(self):
|
def _updateFirstEmpty(self):
|
||||||
for i, a in enumerate(self._arrange):
|
for i, a in enumerate(self._arrange):
|
||||||
if a.isEmpty:
|
if a.isEmpty:
|
||||||
self._first_empty = i
|
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)
|
new_arrange = Arrange.create(x = self._x, y = self._y, fixed_nodes = self._fixed_nodes)
|
||||||
self._arrange.append(new_arrange)
|
self._arrange.append(new_arrange)
|
||||||
self._count += 1
|
self._count += 1
|
||||||
self._update_first_empty()
|
self._updateFirstEmpty()
|
||||||
|
|
||||||
def count(self):
|
def count(self):
|
||||||
return self._count
|
return self._count
|
||||||
|
|
|
@ -2,12 +2,16 @@
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from PyQt5.QtCore import QTimer
|
from PyQt5.QtCore import QTimer
|
||||||
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
|
|
||||||
class AutoSave:
|
class AutoSave:
|
||||||
def __init__(self, application):
|
def __init__(self, application: "CuraApplication") -> None:
|
||||||
self._application = application
|
self._application = application
|
||||||
self._application.getPreferences().preferenceChanged.connect(self._triggerTimer)
|
self._application.getPreferences().preferenceChanged.connect(self._triggerTimer)
|
||||||
|
|
||||||
|
@ -22,14 +26,14 @@ class AutoSave:
|
||||||
self._enabled = True
|
self._enabled = True
|
||||||
self._saving = False
|
self._saving = False
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self) -> None:
|
||||||
# only initialise if the application is created and has started
|
# only initialise if the application is created and has started
|
||||||
self._change_timer.timeout.connect(self._onTimeout)
|
self._change_timer.timeout.connect(self._onTimeout)
|
||||||
self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||||
self._onGlobalStackChanged()
|
self._onGlobalStackChanged()
|
||||||
self._triggerTimer()
|
self._triggerTimer()
|
||||||
|
|
||||||
def _triggerTimer(self, *args):
|
def _triggerTimer(self, *args: Any) -> None:
|
||||||
if not self._saving:
|
if not self._saving:
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
|
|
||||||
|
@ -40,7 +44,7 @@ class AutoSave:
|
||||||
else:
|
else:
|
||||||
self._change_timer.stop()
|
self._change_timer.stop()
|
||||||
|
|
||||||
def _onGlobalStackChanged(self):
|
def _onGlobalStackChanged(self) -> None:
|
||||||
if self._global_stack:
|
if self._global_stack:
|
||||||
self._global_stack.propertyChanged.disconnect(self._triggerTimer)
|
self._global_stack.propertyChanged.disconnect(self._triggerTimer)
|
||||||
self._global_stack.containersChanged.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.propertyChanged.connect(self._triggerTimer)
|
||||||
self._global_stack.containersChanged.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.
|
self._saving = True # To prevent the save process from triggering another autosave.
|
||||||
Logger.log("d", "Autosaving preferences, instances and profiles")
|
Logger.log("d", "Autosaving preferences, instances and profiles")
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
# Copyright (c) 2019 Ultimaker B.V.
|
# Copyright (c) 2019 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# 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 UM.Mesh.MeshData import MeshData
|
||||||
from cura.Scene.CuraSceneNode import CuraSceneNode
|
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
|
||||||
from UM.Application import Application #To modify the maximum zoom level.
|
from UM.Application import Application #To modify the maximum zoom level.
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Scene.Platform import Platform
|
from UM.Scene.Platform import Platform
|
||||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Resources import Resources
|
from UM.Resources import Resources
|
||||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
from UM.Math.Matrix import Matrix
|
from UM.Math.Matrix import Matrix
|
||||||
from UM.Math.Color import Color
|
from UM.Math.Color import Color
|
||||||
|
@ -17,23 +23,23 @@ from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||||
from UM.Math.Polygon import Polygon
|
from UM.Math.Polygon import Polygon
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
from PyQt5.QtCore import QTimer
|
|
||||||
from UM.View.RenderBatch import RenderBatch
|
from UM.View.RenderBatch import RenderBatch
|
||||||
from UM.View.GL.OpenGL import OpenGL
|
from UM.View.GL.OpenGL import OpenGL
|
||||||
|
|
||||||
from cura.Settings.GlobalStack import GlobalStack
|
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:
|
if TYPE_CHECKING:
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from cura.Settings.ExtruderStack import ExtruderStack
|
from cura.Settings.ExtruderStack import ExtruderStack
|
||||||
from UM.Settings.ContainerStack import ContainerStack
|
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.
|
# Radius of disallowed area in mm around prime. I.e. how much distance to keep from prime position.
|
||||||
PRIME_CLEARANCE = 6.5
|
PRIME_CLEARANCE = 6.5
|
||||||
|
|
||||||
|
@ -1012,13 +1018,13 @@ class BuildVolume(SceneNode):
|
||||||
all_values = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, "value")
|
all_values = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, "value")
|
||||||
all_types = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, "type")
|
all_types = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, "type")
|
||||||
for i, (setting_value, setting_type) in enumerate(zip(all_values, all_types)):
|
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
|
all_values[i] = 0
|
||||||
return all_values
|
return all_values
|
||||||
|
|
||||||
def _calculateBedAdhesionSize(self, used_extruders):
|
def _calculateBedAdhesionSize(self, used_extruders):
|
||||||
if self._global_container_stack is None:
|
if self._global_container_stack is None:
|
||||||
return
|
return None
|
||||||
|
|
||||||
container_stack = self._global_container_stack
|
container_stack = self._global_container_stack
|
||||||
adhesion_type = container_stack.getProperty("adhesion_type", "value")
|
adhesion_type = container_stack.getProperty("adhesion_type", "value")
|
||||||
|
|
|
@ -58,6 +58,8 @@ class CrashHandler:
|
||||||
self.traceback = tb
|
self.traceback = tb
|
||||||
self.has_started = has_started
|
self.has_started = has_started
|
||||||
self.dialog = None # Don't create a QDialog before there is a QApplication
|
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!")
|
Logger.log("c", "An uncaught error has occurred!")
|
||||||
for line in traceback.format_exception(exception_type, value, tb):
|
for line in traceback.format_exception(exception_type, value, tb):
|
||||||
|
|
|
@ -3,17 +3,15 @@
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, QUrl
|
from PyQt5.QtCore import QObject, QUrl
|
||||||
from PyQt5.QtGui import QDesktopServices
|
from PyQt5.QtGui import QDesktopServices
|
||||||
from typing import List, Optional, cast
|
from typing import List, cast
|
||||||
|
|
||||||
from UM.Event import CallFunctionEvent
|
from UM.Event import CallFunctionEvent
|
||||||
from UM.FlameProfiler import pyqtSlot
|
from UM.FlameProfiler import pyqtSlot
|
||||||
from UM.Math.Quaternion import Quaternion
|
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
from UM.Scene.Selection import Selection
|
from UM.Scene.Selection import Selection
|
||||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||||
from UM.Operations.GroupedOperation import GroupedOperation
|
from UM.Operations.GroupedOperation import GroupedOperation
|
||||||
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
||||||
from UM.Operations.RotateOperation import RotateOperation
|
|
||||||
from UM.Operations.TranslateOperation import TranslateOperation
|
from UM.Operations.TranslateOperation import TranslateOperation
|
||||||
|
|
||||||
import cura.CuraApplication
|
import cura.CuraApplication
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from typing import cast, TYPE_CHECKING, Optional, Callable, List
|
from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qm
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Decorators import override, deprecated
|
from UM.Decorators import override
|
||||||
from UM.FlameProfiler import pyqtSlot
|
from UM.FlameProfiler import pyqtSlot
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
|
@ -193,7 +193,7 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
self._cura_package_manager = None
|
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_container = None # type: EmptyInstanceContainer
|
||||||
self.empty_definition_changes_container = None # type: EmptyInstanceContainer
|
self.empty_definition_changes_container = None # type: EmptyInstanceContainer
|
||||||
|
@ -266,7 +266,6 @@ class CuraApplication(QtApplication):
|
||||||
# Backups
|
# Backups
|
||||||
self._auto_save = None # type: Optional[AutoSave]
|
self._auto_save = None # type: Optional[AutoSave]
|
||||||
|
|
||||||
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
|
|
||||||
self._container_registry_class = CuraContainerRegistry
|
self._container_registry_class = CuraContainerRegistry
|
||||||
# Redefined here in order to please the typing.
|
# Redefined here in order to please the typing.
|
||||||
self._container_registry = None # type: CuraContainerRegistry
|
self._container_registry = None # type: CuraContainerRegistry
|
||||||
|
@ -699,7 +698,7 @@ class CuraApplication(QtApplication):
|
||||||
self._message_box_callback_arguments = []
|
self._message_box_callback_arguments = []
|
||||||
|
|
||||||
# Cura has multiple locations where instance containers need to be saved, so we need to handle this differently.
|
# 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:
|
if not self.started:
|
||||||
# Do not do saving during application start or when data should not be saved on quit.
|
# Do not do saving during application start or when data should not be saved on quit.
|
||||||
return
|
return
|
||||||
|
@ -989,8 +988,8 @@ class CuraApplication(QtApplication):
|
||||||
## Get the machine action manager
|
## Get the machine action manager
|
||||||
# We ignore any *args given to this, as we also register the machine manager as qml singleton.
|
# 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.
|
# It wants to give this function an engine and script engine, but we don't care about that.
|
||||||
def getMachineActionManager(self, *args):
|
def getMachineActionManager(self, *args: Any) -> MachineActionManager.MachineActionManager:
|
||||||
return self._machine_action_manager
|
return cast(MachineActionManager.MachineActionManager, self._machine_action_manager)
|
||||||
|
|
||||||
@pyqtSlot(result = QObject)
|
@pyqtSlot(result = QObject)
|
||||||
def getMaterialManagementModel(self) -> MaterialManagementModel:
|
def getMaterialManagementModel(self) -> MaterialManagementModel:
|
||||||
|
@ -1443,7 +1442,7 @@ class CuraApplication(QtApplication):
|
||||||
if center is not None:
|
if center is not None:
|
||||||
object_centers.append(center)
|
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_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_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)
|
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:
|
if center is not None:
|
||||||
object_centers.append(center)
|
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_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_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)
|
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 = os.path.splitext(f)[1]
|
||||||
extension = extension.lower()
|
extension = extension.lower()
|
||||||
filename = os.path.basename(f)
|
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 a non-slicable file is already being loaded, we prevent loading of any further non-slicable files
|
||||||
if extension in self._non_sliceable_extensions:
|
if extension in self._non_sliceable_extensions:
|
||||||
message = Message(
|
message = Message(
|
||||||
|
@ -1796,8 +1795,8 @@ class CuraApplication(QtApplication):
|
||||||
node.addDecorator(build_plate_decorator)
|
node.addDecorator(build_plate_decorator)
|
||||||
build_plate_decorator.setBuildPlateNumber(target_build_plate)
|
build_plate_decorator.setBuildPlateNumber(target_build_plate)
|
||||||
|
|
||||||
op = AddSceneNodeOperation(node, scene.getRoot())
|
operation = AddSceneNodeOperation(node, scene.getRoot())
|
||||||
op.push()
|
operation.push()
|
||||||
|
|
||||||
node.callDecoration("setActiveExtruder", default_extruder_id)
|
node.callDecoration("setActiveExtruder", default_extruder_id)
|
||||||
scene.sceneChanged.emit(node)
|
scene.sceneChanged.emit(node)
|
||||||
|
@ -1871,7 +1870,6 @@ class CuraApplication(QtApplication):
|
||||||
main_window = QtApplication.getInstance().getMainWindow()
|
main_window = QtApplication.getInstance().getMainWindow()
|
||||||
if main_window:
|
if main_window:
|
||||||
return main_window.width()
|
return main_window.width()
|
||||||
else:
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@pyqtSlot(result = int)
|
@pyqtSlot(result = int)
|
||||||
|
@ -1879,7 +1877,6 @@ class CuraApplication(QtApplication):
|
||||||
main_window = QtApplication.getInstance().getMainWindow()
|
main_window = QtApplication.getInstance().getMainWindow()
|
||||||
if main_window:
|
if main_window:
|
||||||
return main_window.height()
|
return main_window.height()
|
||||||
else:
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# 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.CuraApplication import CuraApplication #To find some resource types.
|
||||||
from cura.Settings.GlobalStack import GlobalStack
|
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.PackageManager import PackageManager #The class we're extending.
|
||||||
from UM.Resources import Resources #To find storage paths for some resource types.
|
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):
|
class CuraPackageManager(PackageManager):
|
||||||
def __init__(self, application, parent = None):
|
def __init__(self, application: "QtApplication", parent: Optional["QObject"] = None) -> None:
|
||||||
super().__init__(application, parent)
|
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["materials"] = Resources.getStoragePath(CuraApplication.ResourceTypes.MaterialInstanceContainer)
|
||||||
self._installation_dirs_dict["qualities"] = Resources.getStoragePath(CuraApplication.ResourceTypes.QualityInstanceContainer)
|
self._installation_dirs_dict["qualities"] = Resources.getStoragePath(CuraApplication.ResourceTypes.QualityInstanceContainer)
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ class CuraView(View):
|
||||||
def mainComponent(self) -> QUrl:
|
def mainComponent(self) -> QUrl:
|
||||||
return self.getDisplayComponent("main")
|
return self.getDisplayComponent("main")
|
||||||
|
|
||||||
|
|
||||||
@pyqtProperty(QUrl, constant = True)
|
@pyqtProperty(QUrl, constant = True)
|
||||||
def stageMenuComponent(self) -> QUrl:
|
def stageMenuComponent(self) -> QUrl:
|
||||||
url = self.getDisplayComponent("menu")
|
url = self.getDisplayComponent("menu")
|
||||||
|
|
|
@ -33,10 +33,10 @@ class Layer:
|
||||||
def elementCount(self):
|
def elementCount(self):
|
||||||
return self._element_count
|
return self._element_count
|
||||||
|
|
||||||
def setHeight(self, height):
|
def setHeight(self, height: float) -> None:
|
||||||
self._height = height
|
self._height = height
|
||||||
|
|
||||||
def setThickness(self, thickness):
|
def setThickness(self, thickness: float) -> None:
|
||||||
self._thickness = thickness
|
self._thickness = thickness
|
||||||
|
|
||||||
def lineMeshVertexCount(self) -> int:
|
def lineMeshVertexCount(self) -> int:
|
||||||
|
|
|
@ -16,7 +16,6 @@ class LayerData(MeshData):
|
||||||
def getLayer(self, layer):
|
def getLayer(self, layer):
|
||||||
if layer in self._layers:
|
if layer in self._layers:
|
||||||
return self._layers[layer]
|
return self._layers[layer]
|
||||||
else:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getLayers(self):
|
def getLayers(self):
|
||||||
|
|
|
@ -9,7 +9,7 @@ from cura.LayerData import LayerData
|
||||||
|
|
||||||
## Simple decorator to indicate a scene node holds layer data.
|
## Simple decorator to indicate a scene node holds layer data.
|
||||||
class LayerDataDecorator(SceneNodeDecorator):
|
class LayerDataDecorator(SceneNodeDecorator):
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._layer_data = None # type: Optional[LayerData]
|
self._layer_data = None # type: Optional[LayerData]
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
# Copyright (c) 2019 Ultimaker B.V.
|
# Copyright (c) 2019 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from UM.Qt.QtApplication import QtApplication
|
|
||||||
from typing import Any, Optional
|
|
||||||
import numpy
|
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
|
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
|
# 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.
|
# 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_line_mesh_mask = None # type: Optional[numpy.ndarray]
|
||||||
self._build_cache_needed_points = None # type: Optional[numpy.ndarray]
|
self._build_cache_needed_points = None # type: Optional[numpy.ndarray]
|
||||||
|
@ -149,17 +150,17 @@ class LayerPolygon:
|
||||||
def getColors(self):
|
def getColors(self):
|
||||||
return self._colors
|
return self._colors
|
||||||
|
|
||||||
def mapLineTypeToColor(self, line_types):
|
def mapLineTypeToColor(self, line_types: numpy.ndarray) -> numpy.ndarray:
|
||||||
return self._color_map[line_types]
|
return self._color_map[line_types]
|
||||||
|
|
||||||
def isInfillOrSkinType(self, line_types):
|
def isInfillOrSkinType(self, line_types: numpy.ndarray) -> numpy.ndarray:
|
||||||
return self._isInfillOrSkinTypeMap[line_types]
|
return self._is_infill_or_skin_type_map[line_types]
|
||||||
|
|
||||||
def lineMeshVertexCount(self):
|
def lineMeshVertexCount(self) -> int:
|
||||||
return (self._vertex_end - self._vertex_begin)
|
return self._vertex_end - self._vertex_begin
|
||||||
|
|
||||||
def lineMeshElementCount(self):
|
def lineMeshElementCount(self) -> int:
|
||||||
return (self._index_end - self._index_begin)
|
return self._index_end - self._index_begin
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extruder(self):
|
def extruder(self):
|
||||||
|
@ -202,7 +203,7 @@ class LayerPolygon:
|
||||||
return self._jump_count
|
return self._jump_count
|
||||||
|
|
||||||
# Calculate normals for the entire polygon using numpy.
|
# Calculate normals for the entire polygon using numpy.
|
||||||
def getNormals(self):
|
def getNormals(self) -> numpy.ndarray:
|
||||||
normals = numpy.copy(self._data)
|
normals = numpy.copy(self._data)
|
||||||
normals[:, 1] = 0.0 # We are only interested in 2D normals
|
normals[:, 1] = 0.0 # We are only interested in 2D normals
|
||||||
|
|
||||||
|
@ -226,13 +227,13 @@ class LayerPolygon:
|
||||||
|
|
||||||
return normals
|
return normals
|
||||||
|
|
||||||
__color_map = None # type: numpy.ndarray[Any]
|
__color_map = None # type: numpy.ndarray
|
||||||
|
|
||||||
## Gets the instance of the VersionUpgradeManager, or creates one.
|
## Gets the instance of the VersionUpgradeManager, or creates one.
|
||||||
@classmethod
|
@classmethod
|
||||||
def getColorMap(cls):
|
def getColorMap(cls) -> numpy.ndarray:
|
||||||
if cls.__color_map is None:
|
if cls.__color_map is None:
|
||||||
theme = QtApplication.getInstance().getTheme()
|
theme = cast(Theme, QtApplication.getInstance().getTheme())
|
||||||
cls.__color_map = numpy.array([
|
cls.__color_map = numpy.array([
|
||||||
theme.getColor("layerview_none").getRgbF(), # NoneType
|
theme.getColor("layerview_none").getRgbF(), # NoneType
|
||||||
theme.getColor("layerview_inset_0").getRgbF(), # Inset0Type
|
theme.getColor("layerview_inset_0").getRgbF(), # Inset0Type
|
||||||
|
|
|
@ -26,7 +26,7 @@ class ContainerNode:
|
||||||
## Gets the metadata of the container that this node represents.
|
## Gets the metadata of the container that this node represents.
|
||||||
# Getting the metadata from the container directly is about 10x as fast.
|
# Getting the metadata from the container directly is about 10x as fast.
|
||||||
# \return The metadata of the container in this node.
|
# \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]
|
return ContainerRegistry.getInstance().findContainersMetadata(id = self.container_id)[0]
|
||||||
|
|
||||||
## Get an entry from the metadata of the container that this node contains.
|
## 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
|
# nodes that have children) but that child node may be a node representing the
|
||||||
# empty instance container.
|
# empty instance container.
|
||||||
class ContainerTree:
|
class ContainerTree:
|
||||||
__instance = None
|
__instance = None # type: Optional["ContainerTree"]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getInstance(cls):
|
def getInstance(cls):
|
||||||
|
@ -75,7 +75,7 @@ class ContainerTree:
|
||||||
return self.machines[global_stack.definition.getId()].getQualityChangesGroups(variant_names, material_bases, extruder_enabled)
|
return self.machines[global_stack.definition.getId()].getQualityChangesGroups(variant_names, material_bases, extruder_enabled)
|
||||||
|
|
||||||
## Ran after completely starting up the application.
|
## 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.
|
currently_added = ContainerRegistry.getInstance().findContainerStacks() # Find all currently added global stacks.
|
||||||
JobQueue.getInstance().add(self._MachineNodeLoadJob(self, currently_added))
|
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
|
# \param container_stacks All of the stacks to pre-load the container
|
||||||
# trees for. This needs to be provided from here because the stacks
|
# trees for. This needs to be provided from here because the stacks
|
||||||
# need to be constructed on the main thread because they are QObject.
|
# 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.tree_root = tree_root
|
||||||
self.container_stacks = container_stacks
|
self.container_stacks = container_stacks
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
|
@ -6,13 +6,13 @@ import time
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtProperty
|
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.Logger import Logger
|
||||||
from UM.Settings.SettingDefinition import SettingDefinition
|
from UM.Settings.SettingDefinition import SettingDefinition
|
||||||
from UM.Settings.Validator import ValidatorState
|
from UM.Settings.Validator import ValidatorState
|
||||||
|
|
||||||
|
import cura.CuraApplication
|
||||||
#
|
#
|
||||||
# This class performs setting error checks for the currently active machine.
|
# This class performs setting error checks for the currently active machine.
|
||||||
#
|
#
|
||||||
|
@ -24,25 +24,25 @@ from UM.Settings.Validator import ValidatorState
|
||||||
#
|
#
|
||||||
class MachineErrorChecker(QObject):
|
class MachineErrorChecker(QObject):
|
||||||
|
|
||||||
def __init__(self, parent = None):
|
def __init__(self, parent: Optional[QObject] = None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
self._global_stack = None
|
self._global_stack = None
|
||||||
|
|
||||||
self._has_errors = True # Result of the error check, indicating whether there are errors in the stack
|
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 = set() # type: Set[str] # 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_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
|
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.
|
# 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._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._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
|
# This timer delays the starting of error check so we can react less frequently if the user is frequently
|
||||||
# changing settings.
|
# changing settings.
|
||||||
|
@ -94,13 +94,13 @@ class MachineErrorChecker(QObject):
|
||||||
|
|
||||||
# Start the error check for property changed
|
# Start the error check for property changed
|
||||||
# this is seperate from the startErrorCheck because it ignores a number property types
|
# 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":
|
if property_name != "value":
|
||||||
return
|
return
|
||||||
self.startErrorCheck()
|
self.startErrorCheck()
|
||||||
|
|
||||||
# Starts the error check timer to schedule a new error check.
|
# 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:
|
if not self._check_in_progress:
|
||||||
self._need_to_check = True
|
self._need_to_check = True
|
||||||
self.needToWaitForResultChanged.emit()
|
self.needToWaitForResultChanged.emit()
|
||||||
|
|
|
@ -176,9 +176,9 @@ class MachineNode(ContainerNode):
|
||||||
|
|
||||||
# Find the global qualities for this printer.
|
# 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.
|
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.
|
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()]
|
global_qualities = [cura.CuraApplication.CuraApplication.getInstance().empty_quality_container.getMetaData()]
|
||||||
for global_quality in global_qualities:
|
for global_quality in global_qualities:
|
||||||
self.global_qualities[global_quality["quality_type"]] = QualityNode(global_quality["id"], parent = self)
|
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 typing import Dict
|
||||||
from cura.Machines.VariantNode import VariantNode
|
from cura.Machines.VariantNode import VariantNode
|
||||||
|
|
||||||
|
|
||||||
## Represents a material in the container tree.
|
## Represents a material in the container tree.
|
||||||
#
|
#
|
||||||
# Its subcontainers are quality profiles.
|
# Its subcontainers are quality profiles.
|
||||||
|
|
|
@ -34,7 +34,7 @@ class MaterialBrandsModel(BaseMaterialsModel):
|
||||||
brand_item_list = []
|
brand_item_list = []
|
||||||
brand_group_dict = {}
|
brand_group_dict = {}
|
||||||
|
|
||||||
# Part 1: Generate the entire tree of brands -> material types -> spcific materials
|
# Part 1: Generate the entire tree of brands -> material types -> specific materials
|
||||||
for root_material_id, container_node in self._available_materials.items():
|
for root_material_id, container_node in self._available_materials.items():
|
||||||
# Do not include the materials from a to-be-removed package
|
# Do not include the materials from a to-be-removed package
|
||||||
if bool(container_node.getMetaDataEntry("removed", False)):
|
if bool(container_node.getMetaDataEntry("removed", False)):
|
||||||
|
|
|
@ -51,7 +51,7 @@ class VariantNode(ContainerNode):
|
||||||
# Find all the materials for this variant's name.
|
# Find all the materials for this variant's name.
|
||||||
else: # Printer has its own material profiles. Look for material profiles with this printer's definition.
|
else: # Printer has its own material profiles. Look for material profiles with this printer's definition.
|
||||||
base_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = "fdmprinter")
|
base_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = "fdmprinter")
|
||||||
printer_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.machine.container_id, variant_name = None)
|
printer_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.machine.container_id)
|
||||||
variant_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.machine.container_id, variant_name = self.variant_name) # If empty_variant, this won't return anything.
|
variant_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.machine.container_id, variant_name = self.variant_name) # If empty_variant, this won't return anything.
|
||||||
materials_per_base_file = {material["base_file"]: material for material in base_materials}
|
materials_per_base_file = {material["base_file"]: material for material in base_materials}
|
||||||
materials_per_base_file.update({material["base_file"]: material for material in printer_specific_materials}) # Printer-specific profiles override global ones.
|
materials_per_base_file.update({material["base_file"]: material for material in printer_specific_materials}) # Printer-specific profiles override global ones.
|
||||||
|
|
|
@ -47,7 +47,7 @@ class MultiplyObjectsJob(Job):
|
||||||
nodes = []
|
nodes = []
|
||||||
|
|
||||||
not_fit_count = 0
|
not_fit_count = 0
|
||||||
|
found_solution_for_all = False
|
||||||
for node in self._objects:
|
for node in self._objects:
|
||||||
# If object is part of a group, multiply group
|
# If object is part of a group, multiply group
|
||||||
current_node = node
|
current_node = node
|
||||||
|
@ -66,7 +66,7 @@ class MultiplyObjectsJob(Job):
|
||||||
|
|
||||||
found_solution_for_all = True
|
found_solution_for_all = True
|
||||||
arranger.resetLastPriority()
|
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.
|
# We do place the nodes one by one, as we want to yield in between.
|
||||||
new_node = copy.deepcopy(node)
|
new_node = copy.deepcopy(node)
|
||||||
solution_found = False
|
solution_found = False
|
||||||
|
@ -98,10 +98,10 @@ class MultiplyObjectsJob(Job):
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
|
|
||||||
if nodes:
|
if nodes:
|
||||||
op = GroupedOperation()
|
operation = GroupedOperation()
|
||||||
for new_node in nodes:
|
for new_node in nodes:
|
||||||
op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
|
operation.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
|
||||||
op.push()
|
operation.push()
|
||||||
status_message.hide()
|
status_message.hide()
|
||||||
|
|
||||||
if not found_solution_for_all:
|
if not found_solution_for_all:
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
# Copyright (c) 2019 Ultimaker B.V.
|
# Copyright (c) 2019 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
from typing import Optional
|
from typing import Optional, Dict, Any
|
||||||
|
|
||||||
|
|
||||||
class BaseModel:
|
class BaseModel:
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs: Any) -> None:
|
||||||
self.__dict__.update(kwargs)
|
self.__dict__.update(kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,9 +53,10 @@ class ResponseData(BaseModel):
|
||||||
redirect_uri = None # type: Optional[str]
|
redirect_uri = None # type: Optional[str]
|
||||||
content_type = "text/html" # type: str
|
content_type = "text/html" # type: str
|
||||||
|
|
||||||
|
|
||||||
## Possible HTTP responses.
|
## Possible HTTP responses.
|
||||||
HTTP_STATUS = {
|
HTTP_STATUS = {
|
||||||
"OK": ResponseStatus(code = 200, message = "OK"),
|
"OK": ResponseStatus(code = 200, message = "OK"),
|
||||||
"NOT_FOUND": ResponseStatus(code = 404, message = "NOT FOUND"),
|
"NOT_FOUND": ResponseStatus(code = 404, message = "NOT FOUND"),
|
||||||
"REDIRECT": ResponseStatus(code = 302, message = "REDIRECT")
|
"REDIRECT": ResponseStatus(code = 302, message = "REDIRECT")
|
||||||
}
|
} # type: Dict[str, ResponseStatus]
|
||||||
|
|
|
@ -122,6 +122,6 @@ class _ObjectOrder:
|
||||||
# \param order List of indices in which to print objects, ordered by printing
|
# \param order List of indices in which to print objects, ordered by printing
|
||||||
# order.
|
# order.
|
||||||
# \param todo: List of indices which are not yet inserted into the order list.
|
# \param todo: List of indices which are not yet inserted into the order list.
|
||||||
def __init__(self, order: List[SceneNode], todo: List[SceneNode]):
|
def __init__(self, order: List[SceneNode], todo: List[SceneNode]) -> None:
|
||||||
self.order = order
|
self.order = order
|
||||||
self.todo = todo
|
self.todo = todo
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# 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.Operation import Operation
|
||||||
from UM.Operations.GroupedOperation import GroupedOperation
|
from UM.Operations.GroupedOperation import GroupedOperation
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
|
|
||||||
|
|
||||||
## A specialised operation designed specifically to modify the previous operation.
|
## A specialised operation designed specifically to modify the previous operation.
|
||||||
class PlatformPhysicsOperation(Operation):
|
class PlatformPhysicsOperation(Operation):
|
||||||
def __init__(self, node, translation):
|
def __init__(self, node: SceneNode, translation: Vector) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._node = node
|
self._node = node
|
||||||
self._old_transformation = node.getLocalTransformation()
|
self._old_transformation = node.getLocalTransformation()
|
||||||
self._translation = translation
|
self._translation = translation
|
||||||
self._always_merge = True
|
self._always_merge = True
|
||||||
|
|
||||||
def undo(self):
|
def undo(self) -> None:
|
||||||
self._node.setTransformation(self._old_transformation)
|
self._node.setTransformation(self._old_transformation)
|
||||||
|
|
||||||
def redo(self):
|
def redo(self) -> None:
|
||||||
self._node.translate(self._translation, SceneNode.TransformSpace.World)
|
self._node.translate(self._translation, SceneNode.TransformSpace.World)
|
||||||
|
|
||||||
def mergeWith(self, other):
|
def mergeWith(self, other: Operation) -> GroupedOperation:
|
||||||
group = GroupedOperation()
|
group = GroupedOperation()
|
||||||
|
|
||||||
group.addOperation(other)
|
group.addOperation(other)
|
||||||
|
@ -28,5 +29,5 @@ class PlatformPhysicsOperation(Operation):
|
||||||
|
|
||||||
return group
|
return group
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
return "PlatformPhysicsOp.(trans.={0})".format(self._translation)
|
return "PlatformPhysicsOp.(trans.={0})".format(self._translation)
|
||||||
|
|
|
@ -6,9 +6,9 @@ from UM.Operations.Operation import Operation
|
||||||
|
|
||||||
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
||||||
|
|
||||||
|
|
||||||
## Simple operation to set the buildplate number of a scenenode.
|
## Simple operation to set the buildplate number of a scenenode.
|
||||||
class SetBuildPlateNumberOperation(Operation):
|
class SetBuildPlateNumberOperation(Operation):
|
||||||
|
|
||||||
def __init__(self, node: SceneNode, build_plate_nr: int) -> None:
|
def __init__(self, node: SceneNode, build_plate_nr: int) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._node = node
|
self._node = node
|
||||||
|
@ -16,11 +16,11 @@ class SetBuildPlateNumberOperation(Operation):
|
||||||
self._previous_build_plate_nr = None
|
self._previous_build_plate_nr = None
|
||||||
self._decorator_added = False
|
self._decorator_added = False
|
||||||
|
|
||||||
def undo(self):
|
def undo(self) -> None:
|
||||||
if self._previous_build_plate_nr:
|
if self._previous_build_plate_nr:
|
||||||
self._node.callDecoration("setBuildPlateNumber", 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.
|
stack = self._node.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway.
|
||||||
if not stack:
|
if not stack:
|
||||||
self._node.addDecorator(SettingOverrideDecorator())
|
self._node.addDecorator(SettingOverrideDecorator())
|
||||||
|
|
|
@ -1,36 +1,37 @@
|
||||||
# Copyright (c) 2016 Ultimaker B.V.
|
# Copyright (c) 2016 Ultimaker B.V.
|
||||||
# Uranium is released under the terms of the LGPLv3 or higher.
|
# Uranium is released under the terms of the LGPLv3 or higher.
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Operations import Operation
|
from UM.Operations import Operation
|
||||||
|
|
||||||
from UM.Math.Vector import Vector
|
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):
|
class SetParentOperation(Operation.Operation):
|
||||||
## Initialises this SetParentOperation.
|
## Initialises this SetParentOperation.
|
||||||
#
|
#
|
||||||
# \param node The node which will be reparented.
|
# \param node The node which will be reparented.
|
||||||
# \param parent_node The node which will be the parent.
|
# \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]) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._node = node
|
self._node = node
|
||||||
self._parent = parent_node
|
self._parent = parent_node
|
||||||
self._old_parent = node.getParent() # To restore the previous parent in case of an undo.
|
self._old_parent = node.getParent() # To restore the previous parent in case of an undo.
|
||||||
|
|
||||||
## Undoes the set-parent operation, restoring the old parent.
|
## Undoes the set-parent operation, restoring the old parent.
|
||||||
def undo(self):
|
def undo(self) -> None:
|
||||||
self._set_parent(self._old_parent)
|
self._set_parent(self._old_parent)
|
||||||
|
|
||||||
## Re-applies the set-parent operation.
|
## Re-applies the set-parent operation.
|
||||||
def redo(self):
|
def redo(self) -> None:
|
||||||
self._set_parent(self._parent)
|
self._set_parent(self._parent)
|
||||||
|
|
||||||
## Sets the parent of the node while applying transformations to the world-transform of the node stays the same.
|
## 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.
|
# \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:
|
if new_parent:
|
||||||
current_parent = self._node.getParent()
|
current_parent = self._node.getParent()
|
||||||
if current_parent:
|
if current_parent:
|
||||||
|
@ -59,5 +60,5 @@ class SetParentOperation(Operation.Operation):
|
||||||
## Returns a programmer-readable representation of this operation.
|
## Returns a programmer-readable representation of this operation.
|
||||||
#
|
#
|
||||||
# \return 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)
|
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:
|
if TYPE_CHECKING:
|
||||||
from UM.View.GL.ShaderProgram import ShaderProgram
|
from UM.View.GL.ShaderProgram import ShaderProgram
|
||||||
|
|
||||||
MYPY = False
|
|
||||||
if MYPY:
|
|
||||||
from UM.Scene.Camera import Camera
|
from UM.Scene.Camera import Camera
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from PyQt5.QtQuick import QQuickImageProvider
|
||||||
from PyQt5.QtCore import QSize
|
from PyQt5.QtCore import QSize
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
|
||||||
class PrintJobPreviewImageProvider(QQuickImageProvider):
|
class PrintJobPreviewImageProvider(QQuickImageProvider):
|
||||||
|
@ -10,7 +11,7 @@ class PrintJobPreviewImageProvider(QQuickImageProvider):
|
||||||
super().__init__(QQuickImageProvider.Image)
|
super().__init__(QQuickImageProvider.Image)
|
||||||
|
|
||||||
## Request a new 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
|
# 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.
|
# increment, we need to strip that first.
|
||||||
uuid = id[id.find("/") + 1:]
|
uuid = id[id.find("/") + 1:]
|
||||||
|
@ -22,6 +23,6 @@ class PrintJobPreviewImageProvider(QQuickImageProvider):
|
||||||
if print_job.key == uuid:
|
if print_job.key == uuid:
|
||||||
if print_job.getPreviewImage():
|
if print_job.getPreviewImage():
|
||||||
return print_job.getPreviewImage(), QSize(15, 15)
|
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._time_elapsed = new_time_elapsed
|
||||||
self.timeElapsedChanged.emit()
|
self.timeElapsedChanged.emit()
|
||||||
|
|
||||||
def updateState(self, new_state):
|
def updateState(self, new_state: str) -> None:
|
||||||
if self._state != new_state:
|
if self._state != new_state:
|
||||||
self._state = new_state
|
self._state = new_state
|
||||||
self.stateChanged.emit()
|
self.stateChanged.emit()
|
||||||
|
|
|
@ -148,7 +148,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
|
||||||
|
|
||||||
@pyqtProperty(QObject, notify = printersChanged)
|
@pyqtProperty(QObject, notify = printersChanged)
|
||||||
def activePrinter(self) -> Optional["PrinterOutputModel"]:
|
def activePrinter(self) -> Optional["PrinterOutputModel"]:
|
||||||
if len(self._printers):
|
if self._printers:
|
||||||
return self._printers[0]
|
return self._printers[0]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -10,3 +10,6 @@ class BlockSlicingDecorator(SceneNodeDecorator):
|
||||||
|
|
||||||
def isBlockSlicing(self) -> bool:
|
def isBlockSlicing(self) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
return BlockSlicingDecorator()
|
|
@ -17,8 +17,8 @@ class GCodeListDecorator(SceneNodeDecorator):
|
||||||
def getGCodeList(self) -> List[str]:
|
def getGCodeList(self) -> List[str]:
|
||||||
return self._gcode_list
|
return self._gcode_list
|
||||||
|
|
||||||
def setGCodeList(self, list: List[str]) -> None:
|
def setGCodeList(self, gcode_list: List[str]) -> None:
|
||||||
self._gcode_list = list
|
self._gcode_list = gcode_list
|
||||||
|
|
||||||
def __deepcopy__(self, memo) -> "GCodeListDecorator":
|
def __deepcopy__(self, memo) -> "GCodeListDecorator":
|
||||||
copied_decorator = GCodeListDecorator()
|
copied_decorator = GCodeListDecorator()
|
||||||
|
|
|
@ -15,7 +15,6 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
from UM.Settings.ContainerStack import ContainerStack
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer
|
from UM.Settings.InstanceContainer import InstanceContainer
|
||||||
from UM.Settings.SettingInstance import SettingInstance
|
from UM.Settings.SettingInstance import SettingInstance
|
||||||
from UM.Application import Application
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.Platform import Platform
|
from UM.Platform import Platform
|
||||||
|
@ -176,7 +175,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||||
if not file_name:
|
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")}
|
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:
|
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)}
|
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()
|
container_tree = ContainerTree.getInstance()
|
||||||
|
@ -384,7 +383,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||||
if not quality_type:
|
if not quality_type:
|
||||||
return catalog.i18nc("@info:status", "Profile is missing a 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:
|
if global_stack is None:
|
||||||
return None
|
return None
|
||||||
definition_id = ContainerTree.getInstance().machines[global_stack.definition.getId()].quality_definition
|
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
|
# Dict of all actions that need to be done when first added by definition ID
|
||||||
self._first_start_actions = {} # type: Dict[str, List[MachineAction]]
|
self._first_start_actions = {} # type: Dict[str, List[MachineAction]]
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self) -> None:
|
||||||
# Add machine_action as plugin type
|
# Add machine_action as plugin type
|
||||||
PluginRegistry.addType("machine_action", self.addMachineAction)
|
PluginRegistry.addType("machine_action", self.addMachineAction)
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ class GCodeStep():
|
||||||
Class to store the current value of each G_Code parameter
|
Class to store the current value of each G_Code parameter
|
||||||
for any G-Code step
|
for any G-Code step
|
||||||
"""
|
"""
|
||||||
def __init__(self, step, in_relative_movement: bool = False):
|
def __init__(self, step, in_relative_movement: bool = False) -> None:
|
||||||
self.step = step
|
self.step = step
|
||||||
self.step_x = 0
|
self.step_x = 0
|
||||||
self.step_y = 0
|
self.step_y = 0
|
||||||
|
|
|
@ -11,7 +11,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class SimulationViewProxy(QObject):
|
class SimulationViewProxy(QObject):
|
||||||
def __init__(self, simulation_view: "SimulationView", parent=None):
|
def __init__(self, simulation_view: "SimulationView", parent=None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._simulation_view = simulation_view
|
self._simulation_view = simulation_view
|
||||||
self._current_layer = 0
|
self._current_layer = 0
|
||||||
|
|
|
@ -74,7 +74,7 @@ UM.Dialog{
|
||||||
}
|
}
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
text: model.name
|
text: model.display_name
|
||||||
font: UM.Theme.getFont("medium_bold")
|
font: UM.Theme.getFont("medium_bold")
|
||||||
anchors.left: packageIcon.right
|
anchors.left: packageIcon.right
|
||||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||||
|
@ -104,7 +104,7 @@ UM.Dialog{
|
||||||
{
|
{
|
||||||
width: parent.width
|
width: parent.width
|
||||||
property int lineHeight: 60
|
property int lineHeight: 60
|
||||||
visible: !model.is_compatible
|
visible: !model.is_compatible && !model.is_dismissed
|
||||||
height: visible ? (lineHeight + UM.Theme.getSize("default_margin").height) : 0 // We only show the incompatible packages here
|
height: visible ? (lineHeight + UM.Theme.getSize("default_margin").height) : 0 // We only show the incompatible packages here
|
||||||
Image
|
Image
|
||||||
{
|
{
|
||||||
|
@ -117,7 +117,7 @@ UM.Dialog{
|
||||||
}
|
}
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
text: model.name
|
text: model.display_name
|
||||||
font: UM.Theme.getFont("medium_bold")
|
font: UM.Theme.getFont("medium_bold")
|
||||||
anchors.left: packageIcon.right
|
anchors.left: packageIcon.right
|
||||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||||
|
@ -125,6 +125,26 @@ UM.Dialog{
|
||||||
color: UM.Theme.getColor("text")
|
color: UM.Theme.getColor("text")
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
|
UM.TooltipArea
|
||||||
|
{
|
||||||
|
width: childrenRect.width;
|
||||||
|
height: childrenRect.height;
|
||||||
|
text: catalog.i18nc("@info:tooltip", "Dismisses the package and won't be shown in this dialog anymore")
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: packageIcon.verticalCenter
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
text: "(Dismiss)"
|
||||||
|
font: UM.Theme.getFont("small")
|
||||||
|
color: UM.Theme.getColor("text")
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: toolbox.dismissIncompatiblePackage(model.package_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
# Copyright (c) 2020 Ultimaker B.V.
|
# Copyright (c) 2020 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, pyqtProperty
|
from PyQt5.QtCore import Qt, pyqtProperty, pyqtSlot
|
||||||
from UM.Qt.ListModel import ListModel
|
from UM.Qt.ListModel import ListModel
|
||||||
from cura import ApplicationMetadata
|
from cura import ApplicationMetadata
|
||||||
|
from UM.Logger import Logger
|
||||||
|
from typing import List, Dict, Any
|
||||||
|
|
||||||
|
|
||||||
class SubscribedPackagesModel(ListModel):
|
class SubscribedPackagesModel(ListModel):
|
||||||
|
@ -15,9 +17,11 @@ class SubscribedPackagesModel(ListModel):
|
||||||
self._discrepancies = None
|
self._discrepancies = None
|
||||||
self._sdk_version = ApplicationMetadata.CuraSDKVersion
|
self._sdk_version = ApplicationMetadata.CuraSDKVersion
|
||||||
|
|
||||||
self.addRoleName(Qt.UserRole + 1, "name")
|
self.addRoleName(Qt.UserRole + 1, "package_id")
|
||||||
self.addRoleName(Qt.UserRole + 2, "icon_url")
|
self.addRoleName(Qt.UserRole + 2, "display_name")
|
||||||
self.addRoleName(Qt.UserRole + 3, "is_compatible")
|
self.addRoleName(Qt.UserRole + 3, "icon_url")
|
||||||
|
self.addRoleName(Qt.UserRole + 4, "is_compatible")
|
||||||
|
self.addRoleName(Qt.UserRole + 5, "is_dismissed")
|
||||||
|
|
||||||
@pyqtProperty(bool, constant=True)
|
@pyqtProperty(bool, constant=True)
|
||||||
def hasCompatiblePackages(self) -> bool:
|
def hasCompatiblePackages(self) -> bool:
|
||||||
|
@ -33,29 +37,36 @@ class SubscribedPackagesModel(ListModel):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def setMetadata(self, data):
|
# Sets the "is_compatible" to True for the given package, in memory
|
||||||
if self._metadata != data:
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def dismissPackage(self, package_id: str) -> None:
|
||||||
|
package = self.find(key="package_id", value=package_id)
|
||||||
|
if package != -1:
|
||||||
|
self.setProperty(package, property="is_dismissed", value=True)
|
||||||
|
Logger.debug("Package {} has been dismissed".format(package_id))
|
||||||
|
|
||||||
|
def setMetadata(self, data: List[Dict[str, List[Any]]]) -> None:
|
||||||
self._metadata = data
|
self._metadata = data
|
||||||
|
|
||||||
def addValue(self, discrepancy):
|
def addDiscrepancies(self, discrepancy: List[str]) -> None:
|
||||||
if self._discrepancies != discrepancy:
|
|
||||||
self._discrepancies = discrepancy
|
self._discrepancies = discrepancy
|
||||||
|
|
||||||
def getCompatiblePackages(self):
|
def getCompatiblePackages(self):
|
||||||
return [x for x in self._items if x["is_compatible"]]
|
return [x for x in self._items if x["is_compatible"]]
|
||||||
|
|
||||||
def update(self):
|
def initialize(self) -> None:
|
||||||
self._items.clear()
|
self._items.clear()
|
||||||
|
|
||||||
for item in self._metadata:
|
for item in self._metadata:
|
||||||
if item["package_id"] not in self._discrepancies:
|
if item["package_id"] not in self._discrepancies:
|
||||||
continue
|
continue
|
||||||
package = {
|
package = {
|
||||||
"package_id": item["package_id"],
|
"package_id": item["package_id"],
|
||||||
"name": item["display_name"],
|
"display_name": item["display_name"],
|
||||||
"sdk_versions": item["sdk_versions"],
|
"sdk_versions": item["sdk_versions"],
|
||||||
"download_url": item["download_url"],
|
"download_url": item["download_url"],
|
||||||
"md5_hash": item["md5_hash"],
|
"md5_hash": item["md5_hash"],
|
||||||
|
"is_dismissed": False,
|
||||||
}
|
}
|
||||||
if self._sdk_version not in item["sdk_versions"]:
|
if self._sdk_version not in item["sdk_versions"]:
|
||||||
package.update({"is_compatible": False})
|
package.update({"is_compatible": False})
|
||||||
|
@ -65,7 +76,6 @@ class SubscribedPackagesModel(ListModel):
|
||||||
package.update({"icon_url": item["icon_url"]})
|
package.update({"icon_url": item["icon_url"]})
|
||||||
except KeyError: # There is no 'icon_url" in the response payload for this package
|
except KeyError: # There is no 'icon_url" in the response payload for this package
|
||||||
package.update({"icon_url": ""})
|
package.update({"icon_url": ""})
|
||||||
|
|
||||||
self._items.append(package)
|
self._items.append(package)
|
||||||
self.setItems(self._items)
|
self.setItems(self._items)
|
||||||
|
|
||||||
|
|
|
@ -528,6 +528,11 @@ class Toolbox(QObject, Extension):
|
||||||
populated += 1
|
populated += 1
|
||||||
return populated == len(self._server_response_data.items())
|
return populated == len(self._server_response_data.items())
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def dismissIncompatiblePackage(self, package_id: str):
|
||||||
|
self._models["subscribed_packages"].dismissPackage(package_id) # sets "is_compatible" to True, in-memory
|
||||||
|
self._package_manager.dismissPackage(package_id) # adds this package_id as dismissed in the user config file
|
||||||
|
|
||||||
# Make API Calls
|
# Make API Calls
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
def _makeRequestByType(self, request_type: str) -> None:
|
def _makeRequestByType(self, request_type: str) -> None:
|
||||||
|
|
|
@ -14,7 +14,7 @@ class ClusterPrinterMaterialStationSlot(ClusterPrintCoreConfiguration):
|
||||||
# \param material_remaining: How much material is remaining on the spool (between 0 and 1, or -1 for missing data).
|
# \param material_remaining: How much material is remaining on the spool (between 0 and 1, or -1 for missing data).
|
||||||
# \param material_empty: Whether the material spool is too empty to be used.
|
# \param material_empty: Whether the material spool is too empty to be used.
|
||||||
def __init__(self, slot_index: int, compatible: bool, material_remaining: float,
|
def __init__(self, slot_index: int, compatible: bool, material_remaining: float,
|
||||||
material_empty: Optional[bool] = False, **kwargs):
|
material_empty: Optional[bool] = False, **kwargs) -> None:
|
||||||
self.slot_index = slot_index
|
self.slot_index = slot_index
|
||||||
self.compatible = compatible
|
self.compatible = compatible
|
||||||
self.material_remaining = material_remaining
|
self.material_remaining = material_remaining
|
||||||
|
|
|
@ -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.
|
// Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import QtQuick 2.7
|
import QtQuick 2.7
|
||||||
|
@ -21,7 +21,16 @@ UM.MainWindow
|
||||||
id: base
|
id: base
|
||||||
|
|
||||||
// Cura application window title
|
// 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")
|
backgroundColor: UM.Theme.getColor("viewport_background")
|
||||||
|
|
||||||
|
@ -244,23 +253,6 @@ UM.MainWindow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Toolbar
|
|
||||||
{
|
|
||||||
// The toolbar is the left bar that is populated by all the tools (which are dynamicly populated by
|
|
||||||
// plugins)
|
|
||||||
id: toolbar
|
|
||||||
|
|
||||||
property int mouseX: base.mouseX
|
|
||||||
property int mouseY: base.mouseY
|
|
||||||
|
|
||||||
anchors
|
|
||||||
{
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
left: parent.left
|
|
||||||
}
|
|
||||||
visible: CuraApplication.platformActivity && !PrintInformation.preSliced
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectSelector
|
ObjectSelector
|
||||||
{
|
{
|
||||||
id: objectSelector
|
id: objectSelector
|
||||||
|
@ -302,6 +294,23 @@ UM.MainWindow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toolbar
|
||||||
|
{
|
||||||
|
// The toolbar is the left bar that is populated by all the tools (which are dynamicly populated by
|
||||||
|
// plugins)
|
||||||
|
id: toolbar
|
||||||
|
|
||||||
|
property int mouseX: base.mouseX
|
||||||
|
property int mouseY: base.mouseY
|
||||||
|
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
left: parent.left
|
||||||
|
}
|
||||||
|
visible: CuraApplication.platformActivity && !PrintInformation.preSliced
|
||||||
|
}
|
||||||
|
|
||||||
// A hint for the loaded content view. Overlay items / controls can safely be placed in this area
|
// A hint for the loaded content view. Overlay items / controls can safely be placed in this area
|
||||||
Item {
|
Item {
|
||||||
id: mainSafeArea
|
id: mainSafeArea
|
||||||
|
|
5
test-in-docker.sh
Executable file
5
test-in-docker.sh
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
sudo rm -rf ./build ./Uranium
|
||||||
|
sudo docker run -it --rm \
|
||||||
|
-v "$(pwd):/srv/cura" ultimaker/cura-build-environment \
|
||||||
|
/srv/cura/docker/build.sh
|
||||||
|
sudo rm -rf ./build ./Uranium
|
Loading…
Add table
Add a link
Reference in a new issue