mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-12 19:49:00 +08:00
Merge remote-tracking branch 'upstream/master' into dagoma_discoultimate
This commit is contained in:
commit
173a05ddb5
@ -56,6 +56,13 @@ function(cura_add_test)
|
|||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
#Add test for import statements which are not compatible with all builds
|
||||||
|
add_test(
|
||||||
|
NAME "invalid-imports"
|
||||||
|
COMMAND ${Python3_EXECUTABLE} scripts/check_invalid_imports.py
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
cura_add_test(NAME pytest-main DIRECTORY ${CMAKE_SOURCE_DIR}/tests PYTHONPATH "${CMAKE_SOURCE_DIR}|${URANIUM_DIR}")
|
cura_add_test(NAME pytest-main DIRECTORY ${CMAKE_SOURCE_DIR}/tests PYTHONPATH "${CMAKE_SOURCE_DIR}|${URANIUM_DIR}")
|
||||||
|
|
||||||
file(GLOB_RECURSE _plugins plugins/*/__init__.py)
|
file(GLOB_RECURSE _plugins plugins/*/__init__.py)
|
||||||
|
@ -28,9 +28,10 @@ class CuraAPI(QObject):
|
|||||||
# The main reason for this is that we want to prevent consumers of API to have a dependency on CuraApplication.
|
# The main reason for this is that we want to prevent consumers of API to have a dependency on CuraApplication.
|
||||||
# Since the API is intended to be used by plugins, the cura application should have already created this.
|
# Since the API is intended to be used by plugins, the cura application should have already created this.
|
||||||
def __new__(cls, application: Optional["CuraApplication"] = None):
|
def __new__(cls, application: Optional["CuraApplication"] = None):
|
||||||
if cls.__instance is None:
|
if cls.__instance is not None:
|
||||||
|
raise RuntimeError("Tried to create singleton '{class_name}' more than once.".format(class_name = CuraAPI.__name__))
|
||||||
if application is None:
|
if application is None:
|
||||||
raise Exception("Upon first time creation, the application must be set.")
|
raise RuntimeError("Upon first time creation, the application must be set.")
|
||||||
cls.__instance = super(CuraAPI, cls).__new__(cls)
|
cls.__instance = super(CuraAPI, cls).__new__(cls)
|
||||||
cls._application = application
|
cls._application = application
|
||||||
return cls.__instance
|
return cls.__instance
|
||||||
|
@ -145,6 +145,14 @@ class Backup:
|
|||||||
# \return Whether we had success or not.
|
# \return Whether we had success or not.
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extractArchive(archive: "ZipFile", target_path: str) -> bool:
|
def _extractArchive(archive: "ZipFile", target_path: str) -> bool:
|
||||||
|
|
||||||
|
# Implement security recommendations: Sanity check on zip files will make it harder to spoof.
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
config_filename = CuraApplication.getInstance().getApplicationName() + ".cfg" # Should be there if valid.
|
||||||
|
if config_filename not in [file.filename for file in archive.filelist]:
|
||||||
|
Logger.logException("e", "Unable to extract the backup due to corruption of compressed file(s).")
|
||||||
|
return False
|
||||||
|
|
||||||
Logger.log("d", "Removing current data in location: %s", target_path)
|
Logger.log("d", "Removing current data in location: %s", target_path)
|
||||||
Resources.factoryReset()
|
Resources.factoryReset()
|
||||||
Logger.log("d", "Extracting backup to location: %s", target_path)
|
Logger.log("d", "Extracting backup to location: %s", target_path)
|
||||||
|
@ -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 os
|
import os
|
||||||
@ -191,8 +191,6 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
self._cura_formula_functions = None # type: Optional[CuraFormulaFunctions]
|
self._cura_formula_functions = None # type: Optional[CuraFormulaFunctions]
|
||||||
|
|
||||||
self._cura_package_manager = None
|
|
||||||
|
|
||||||
self._machine_action_manager = None # type: Optional[MachineActionManager.MachineActionManager]
|
self._machine_action_manager = None # type: Optional[MachineActionManager.MachineActionManager]
|
||||||
|
|
||||||
self.empty_container = None # type: EmptyInstanceContainer
|
self.empty_container = None # type: EmptyInstanceContainer
|
||||||
@ -632,6 +630,12 @@ class CuraApplication(QtApplication):
|
|||||||
def showPreferences(self) -> None:
|
def showPreferences(self) -> None:
|
||||||
self.showPreferencesWindow.emit()
|
self.showPreferencesWindow.emit()
|
||||||
|
|
||||||
|
# This is called by drag-and-dropping curapackage files.
|
||||||
|
@pyqtSlot(QUrl)
|
||||||
|
def installPackageViaDragAndDrop(self, file_url: str) -> Optional[str]:
|
||||||
|
filename = QUrl(file_url).toLocalFile()
|
||||||
|
return self._package_manager.installPackage(filename)
|
||||||
|
|
||||||
@override(Application)
|
@override(Application)
|
||||||
def getGlobalContainerStack(self) -> Optional["GlobalStack"]:
|
def getGlobalContainerStack(self) -> Optional["GlobalStack"]:
|
||||||
return self._global_container_stack
|
return self._global_container_stack
|
||||||
@ -1827,11 +1831,17 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
def _onContextMenuRequested(self, x: float, y: float) -> None:
|
def _onContextMenuRequested(self, x: float, y: float) -> None:
|
||||||
# Ensure we select the object if we request a context menu over an object without having a selection.
|
# Ensure we select the object if we request a context menu over an object without having a selection.
|
||||||
if not Selection.hasSelection():
|
if Selection.hasSelection():
|
||||||
node = self.getController().getScene().findObject(cast(SelectionPass, self.getRenderer().getRenderPass("selection")).getIdAtPosition(x, y))
|
return
|
||||||
if node:
|
selection_pass = cast(SelectionPass, self.getRenderer().getRenderPass("selection"))
|
||||||
|
if not selection_pass: # If you right-click before the rendering has been initialised there might not be a selection pass yet.
|
||||||
|
print("--------------ding! Got the crash.")
|
||||||
|
return
|
||||||
|
node = self.getController().getScene().findObject(selection_pass.getIdAtPosition(x, y))
|
||||||
|
if not node:
|
||||||
|
return
|
||||||
parent = node.getParent()
|
parent = node.getParent()
|
||||||
while(parent and parent.callDecoration("isGroup")):
|
while parent and parent.callDecoration("isGroup"):
|
||||||
node = parent
|
node = parent
|
||||||
parent = node.getParent()
|
parent = node.getParent()
|
||||||
|
|
||||||
|
@ -115,9 +115,10 @@ class AuthorizationHelpers:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
## Generate a 16-character verification code.
|
## Generate a verification code of arbitrary length.
|
||||||
# \param code_length: How long should the code be?
|
# \param code_length: How long should the code be? This should never be lower than 16, but it's probably better to
|
||||||
def generateVerificationCode(code_length: int = 16) -> str:
|
# leave it at 32
|
||||||
|
def generateVerificationCode(code_length: int = 32) -> str:
|
||||||
return "".join(random.choice("0123456789ABCDEF") for i in range(code_length))
|
return "".join(random.choice("0123456789ABCDEF") for i in range(code_length))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -25,6 +25,8 @@ class AuthorizationRequestHandler(BaseHTTPRequestHandler):
|
|||||||
self.authorization_callback = None # type: Optional[Callable[[AuthenticationResponse], None]]
|
self.authorization_callback = None # type: Optional[Callable[[AuthenticationResponse], None]]
|
||||||
self.verification_code = None # type: Optional[str]
|
self.verification_code = None # type: Optional[str]
|
||||||
|
|
||||||
|
self.state = None # type: Optional[str]
|
||||||
|
|
||||||
# CURA-6609: Some browser seems to issue a HEAD instead of GET request as the callback.
|
# CURA-6609: Some browser seems to issue a HEAD instead of GET request as the callback.
|
||||||
def do_HEAD(self) -> None:
|
def do_HEAD(self) -> None:
|
||||||
self.do_GET()
|
self.do_GET()
|
||||||
@ -58,7 +60,14 @@ class AuthorizationRequestHandler(BaseHTTPRequestHandler):
|
|||||||
# \return HTTP ResponseData containing a success page to show to the user.
|
# \return HTTP ResponseData containing a success page to show to the user.
|
||||||
def _handleCallback(self, query: Dict[Any, List]) -> Tuple[ResponseData, Optional[AuthenticationResponse]]:
|
def _handleCallback(self, query: Dict[Any, List]) -> Tuple[ResponseData, Optional[AuthenticationResponse]]:
|
||||||
code = self._queryGet(query, "code")
|
code = self._queryGet(query, "code")
|
||||||
if code and self.authorization_helpers is not None and self.verification_code is not None:
|
state = self._queryGet(query, "state")
|
||||||
|
if state != self.state:
|
||||||
|
token_response = AuthenticationResponse(
|
||||||
|
success = False,
|
||||||
|
err_message=catalog.i18nc("@message",
|
||||||
|
"The provided state is not correct.")
|
||||||
|
)
|
||||||
|
elif code and self.authorization_helpers is not None and self.verification_code is not None:
|
||||||
# If the code was returned we get the access token.
|
# If the code was returned we get the access token.
|
||||||
token_response = self.authorization_helpers.getAccessTokenUsingAuthorizationCode(
|
token_response = self.authorization_helpers.getAccessTokenUsingAuthorizationCode(
|
||||||
code, self.verification_code)
|
code, self.verification_code)
|
||||||
|
@ -25,3 +25,6 @@ class AuthorizationRequestServer(HTTPServer):
|
|||||||
## Set the verification code on the request handler.
|
## Set the verification code on the request handler.
|
||||||
def setVerificationCode(self, verification_code: str) -> None:
|
def setVerificationCode(self, verification_code: str) -> None:
|
||||||
self.RequestHandlerClass.verification_code = verification_code # type: ignore
|
self.RequestHandlerClass.verification_code = verification_code # type: ignore
|
||||||
|
|
||||||
|
def setState(self, state: str) -> None:
|
||||||
|
self.RequestHandlerClass.state = state # type: ignore
|
||||||
|
@ -153,13 +153,15 @@ class AuthorizationService:
|
|||||||
verification_code = self._auth_helpers.generateVerificationCode()
|
verification_code = self._auth_helpers.generateVerificationCode()
|
||||||
challenge_code = self._auth_helpers.generateVerificationCodeChallenge(verification_code)
|
challenge_code = self._auth_helpers.generateVerificationCodeChallenge(verification_code)
|
||||||
|
|
||||||
|
state = AuthorizationHelpers.generateVerificationCode()
|
||||||
|
|
||||||
# Create the query string needed for the OAuth2 flow.
|
# Create the query string needed for the OAuth2 flow.
|
||||||
query_string = urlencode({
|
query_string = urlencode({
|
||||||
"client_id": self._settings.CLIENT_ID,
|
"client_id": self._settings.CLIENT_ID,
|
||||||
"redirect_uri": self._settings.CALLBACK_URL,
|
"redirect_uri": self._settings.CALLBACK_URL,
|
||||||
"scope": self._settings.CLIENT_SCOPES,
|
"scope": self._settings.CLIENT_SCOPES,
|
||||||
"response_type": "code",
|
"response_type": "code",
|
||||||
"state": "(.Y.)",
|
"state": state, # Forever in our Hearts, RIP "(.Y.)" (2018-2020)
|
||||||
"code_challenge": challenge_code,
|
"code_challenge": challenge_code,
|
||||||
"code_challenge_method": "S512"
|
"code_challenge_method": "S512"
|
||||||
})
|
})
|
||||||
@ -168,7 +170,7 @@ class AuthorizationService:
|
|||||||
QDesktopServices.openUrl(QUrl("{}?{}".format(self._auth_url, query_string)))
|
QDesktopServices.openUrl(QUrl("{}?{}".format(self._auth_url, query_string)))
|
||||||
|
|
||||||
# Start a local web server to receive the callback URL on.
|
# Start a local web server to receive the callback URL on.
|
||||||
self._server.start(verification_code)
|
self._server.start(verification_code, state)
|
||||||
|
|
||||||
## Callback method for the authentication flow.
|
## Callback method for the authentication flow.
|
||||||
def _onAuthStateChanged(self, auth_response: AuthenticationResponse) -> None:
|
def _onAuthStateChanged(self, auth_response: AuthenticationResponse) -> None:
|
||||||
|
@ -36,7 +36,8 @@ class LocalAuthorizationServer:
|
|||||||
|
|
||||||
## Starts the local web server to handle the authorization callback.
|
## Starts the local web server to handle the authorization callback.
|
||||||
# \param verification_code The verification code part of the OAuth2 client identification.
|
# \param verification_code The verification code part of the OAuth2 client identification.
|
||||||
def start(self, verification_code: str) -> None:
|
# \param state The unique state code (to ensure that the request we get back is really from the server.
|
||||||
|
def start(self, verification_code: str, state: str) -> None:
|
||||||
if self._web_server:
|
if self._web_server:
|
||||||
# If the server is already running (because of a previously aborted auth flow), we don't have to start it.
|
# If the server is already running (because of a previously aborted auth flow), we don't have to start it.
|
||||||
# We still inject the new verification code though.
|
# We still inject the new verification code though.
|
||||||
@ -53,6 +54,7 @@ class LocalAuthorizationServer:
|
|||||||
self._web_server.setAuthorizationHelpers(self._auth_helpers)
|
self._web_server.setAuthorizationHelpers(self._auth_helpers)
|
||||||
self._web_server.setAuthorizationCallback(self._auth_state_changed_callback)
|
self._web_server.setAuthorizationCallback(self._auth_state_changed_callback)
|
||||||
self._web_server.setVerificationCode(verification_code)
|
self._web_server.setVerificationCode(verification_code)
|
||||||
|
self._web_server.setState(state)
|
||||||
|
|
||||||
# Start the server on a new thread.
|
# Start the server on a new thread.
|
||||||
self._web_server_thread = threading.Thread(None, self._web_server.serve_forever, daemon = self._daemon)
|
self._web_server_thread = threading.Thread(None, self._web_server.serve_forever, daemon = self._daemon)
|
||||||
|
@ -747,6 +747,11 @@ class MachineManager(QObject):
|
|||||||
result = [] # type: List[str]
|
result = [] # type: List[str]
|
||||||
for setting_instance in container.findInstances():
|
for setting_instance in container.findInstances():
|
||||||
setting_key = setting_instance.definition.key
|
setting_key = setting_instance.definition.key
|
||||||
|
if setting_key == "print_sequence":
|
||||||
|
old_value = container.getProperty(setting_key, "value")
|
||||||
|
Logger.log("d", "Reset setting [%s] in [%s] because its old value [%s] is no longer valid", setting_key, container, old_value)
|
||||||
|
result.append(setting_key)
|
||||||
|
continue
|
||||||
if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"):
|
if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -29,9 +29,13 @@ parser.add_argument("--debug",
|
|||||||
known_args = vars(parser.parse_known_args()[0])
|
known_args = vars(parser.parse_known_args()[0])
|
||||||
|
|
||||||
if with_sentry_sdk:
|
if with_sentry_sdk:
|
||||||
sentry_env = "production"
|
sentry_env = "unknown" # Start off with a "IDK"
|
||||||
if ApplicationMetadata.CuraVersion == "master":
|
if hasattr(sys, "frozen"):
|
||||||
|
sentry_env = "production" # A frozen build is a "real" distribution.
|
||||||
|
elif ApplicationMetadata.CuraVersion == "master":
|
||||||
sentry_env = "development"
|
sentry_env = "development"
|
||||||
|
elif "beta" in ApplicationMetadata.CuraVersion or "BETA" in ApplicationMetadata.CuraVersion:
|
||||||
|
sentry_env = "beta"
|
||||||
try:
|
try:
|
||||||
if ApplicationMetadata.CuraVersion.split(".")[2] == "99":
|
if ApplicationMetadata.CuraVersion.split(".")[2] == "99":
|
||||||
sentry_env = "nightly"
|
sentry_env = "nightly"
|
||||||
|
@ -13,6 +13,8 @@ export PKG_CONFIG_PATH="${CURA_BUILD_ENV_PATH}/lib/pkgconfig:${PKG_CONFIG_PATH}"
|
|||||||
|
|
||||||
cd "${PROJECT_DIR}"
|
cd "${PROJECT_DIR}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Clone Uranium and set PYTHONPATH first
|
# Clone Uranium and set PYTHONPATH first
|
||||||
#
|
#
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
import zipfile
|
import zipfile
|
||||||
import os
|
import os
|
||||||
from typing import cast, Dict, List, Optional, Tuple
|
import json
|
||||||
|
from typing import cast, Dict, List, Optional, Tuple, Any
|
||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
@ -732,7 +733,25 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
|
|
||||||
base_file_name = os.path.basename(file_name)
|
base_file_name = os.path.basename(file_name)
|
||||||
self.setWorkspaceName(base_file_name)
|
self.setWorkspaceName(base_file_name)
|
||||||
return nodes
|
|
||||||
|
return nodes, self._loadMetadata(file_name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _loadMetadata(file_name: str) -> Dict[str, Dict[str, Any]]:
|
||||||
|
archive = zipfile.ZipFile(file_name, "r")
|
||||||
|
|
||||||
|
metadata_files = [name for name in archive.namelist() if name.endswith("plugin_metadata.json")]
|
||||||
|
|
||||||
|
result = dict()
|
||||||
|
|
||||||
|
for metadata_file in metadata_files:
|
||||||
|
try:
|
||||||
|
plugin_id = metadata_file.split("/")[0]
|
||||||
|
result[plugin_id] = json.loads(archive.open("%s/plugin_metadata.json" % plugin_id).read().decode("utf-8"))
|
||||||
|
except Exception:
|
||||||
|
Logger.logException("w", "Unable to retrieve metadata for %s", metadata_file)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def _processQualityChanges(self, global_stack):
|
def _processQualityChanges(self, global_stack):
|
||||||
if self._machine_info.quality_changes_info is None:
|
if self._machine_info.quality_changes_info is None:
|
||||||
|
@ -73,11 +73,25 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
|
|||||||
version_config_parser.write(version_file_string)
|
version_config_parser.write(version_file_string)
|
||||||
archive.writestr(version_file, version_file_string.getvalue())
|
archive.writestr(version_file, version_file_string.getvalue())
|
||||||
|
|
||||||
|
self._writePluginMetadataToArchive(archive)
|
||||||
|
|
||||||
# Close the archive & reset states.
|
# Close the archive & reset states.
|
||||||
archive.close()
|
archive.close()
|
||||||
mesh_writer.setStoreArchive(False)
|
mesh_writer.setStoreArchive(False)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _writePluginMetadataToArchive(archive: zipfile.ZipFile) -> None:
|
||||||
|
file_name_template = "%s/plugin_metadata.json"
|
||||||
|
|
||||||
|
for plugin_id, metadata in Application.getInstance().getWorkspaceMetadataStorage().getAllData().items():
|
||||||
|
file_name = file_name_template % plugin_id
|
||||||
|
file_in_archive = zipfile.ZipInfo(file_name)
|
||||||
|
# We have to set the compress type of each file as well (it doesn't keep the type of the entire archive)
|
||||||
|
file_in_archive.compress_type = zipfile.ZIP_DEFLATED
|
||||||
|
import json
|
||||||
|
archive.writestr(file_in_archive, json.dumps(metadata, separators = (", ", ": "), indent = 4, skipkeys = True))
|
||||||
|
|
||||||
## Helper function that writes ContainerStacks, InstanceContainers and DefinitionContainers to the archive.
|
## Helper function that writes ContainerStacks, InstanceContainers and DefinitionContainers to the archive.
|
||||||
# \param container That follows the \type{ContainerInterface} to archive.
|
# \param container That follows the \type{ContainerInterface} to archive.
|
||||||
# \param archive The archive to write to.
|
# \param archive The archive to write to.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2015 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.Mesh.MeshWriter import MeshWriter
|
from UM.Mesh.MeshWriter import MeshWriter
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
@ -40,7 +41,7 @@ class ThreeMFWriter(MeshWriter):
|
|||||||
}
|
}
|
||||||
|
|
||||||
self._unit_matrix_string = self._convertMatrixToString(Matrix())
|
self._unit_matrix_string = self._convertMatrixToString(Matrix())
|
||||||
self._archive = None
|
self._archive = None # type: Optional[zipfile.ZipFile]
|
||||||
self._store_archive = False
|
self._store_archive = False
|
||||||
|
|
||||||
def _convertMatrixToString(self, matrix):
|
def _convertMatrixToString(self, matrix):
|
||||||
|
@ -72,16 +72,23 @@ class DisplayFilenameAndLayerOnLCD(Script):
|
|||||||
lcd_text = "M117 Printing " + name + " - Layer "
|
lcd_text = "M117 Printing " + name + " - Layer "
|
||||||
i = self.getSettingValueByKey("startNum")
|
i = self.getSettingValueByKey("startNum")
|
||||||
for layer in data:
|
for layer in data:
|
||||||
display_text = lcd_text + str(i) + " " + name
|
display_text = lcd_text + str(i)
|
||||||
layer_index = data.index(layer)
|
layer_index = data.index(layer)
|
||||||
lines = layer.split("\n")
|
lines = layer.split("\n")
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.startswith(";LAYER_COUNT:"):
|
if line.startswith(";LAYER_COUNT:"):
|
||||||
max_layer = line
|
max_layer = line
|
||||||
max_layer = max_layer.split(":")[1]
|
max_layer = max_layer.split(":")[1]
|
||||||
|
if self.getSettingValueByKey("startNum") == 0:
|
||||||
|
max_layer = str(int(max_layer) - 1)
|
||||||
if line.startswith(";LAYER:"):
|
if line.startswith(";LAYER:"):
|
||||||
if self.getSettingValueByKey("maxlayer"):
|
if self.getSettingValueByKey("maxlayer"):
|
||||||
display_text = display_text + " of " + max_layer
|
display_text = display_text + " of " + max_layer
|
||||||
|
if not self.getSettingValueByKey("scroll"):
|
||||||
|
display_text = display_text + " " + name
|
||||||
|
else:
|
||||||
|
if not self.getSettingValueByKey("scroll"):
|
||||||
|
display_text = display_text + " " + name + "!"
|
||||||
else:
|
else:
|
||||||
display_text = display_text + "!"
|
display_text = display_text + "!"
|
||||||
line_index = lines.index(line)
|
line_index = lines.index(line)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from ..Script import Script
|
from ..Script import Script
|
||||||
|
|
||||||
|
|
||||||
class TimeLapse(Script):
|
class TimeLapse(Script):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -75,21 +76,29 @@ class TimeLapse(Script):
|
|||||||
trigger_command = self.getSettingValueByKey("trigger_command")
|
trigger_command = self.getSettingValueByKey("trigger_command")
|
||||||
pause_length = self.getSettingValueByKey("pause_length")
|
pause_length = self.getSettingValueByKey("pause_length")
|
||||||
gcode_to_append = ";TimeLapse Begin\n"
|
gcode_to_append = ";TimeLapse Begin\n"
|
||||||
|
last_x = 0
|
||||||
|
last_y = 0
|
||||||
|
|
||||||
if park_print_head:
|
if park_print_head:
|
||||||
gcode_to_append += self.putValue(G = 1, F = feed_rate, X = x_park, Y = y_park) + " ;Park print head\n"
|
gcode_to_append += self.putValue(G=1, F=feed_rate,
|
||||||
|
X=x_park, Y=y_park) + " ;Park print head\n"
|
||||||
gcode_to_append += self.putValue(M=400) + " ;Wait for moves to finish\n"
|
gcode_to_append += self.putValue(M=400) + " ;Wait for moves to finish\n"
|
||||||
gcode_to_append += trigger_command + " ;Snap Photo\n"
|
gcode_to_append += trigger_command + " ;Snap Photo\n"
|
||||||
gcode_to_append += self.putValue(G=4, P=pause_length) + " ;Wait for camera\n"
|
gcode_to_append += self.putValue(G=4, P=pause_length) + " ;Wait for camera\n"
|
||||||
gcode_to_append += ";TimeLapse End\n"
|
|
||||||
for layer in data:
|
for idx, layer in enumerate(data):
|
||||||
|
for line in layer.split("\n"):
|
||||||
|
if self.getValue(line, "G") in {0, 1}: # Track X,Y location.
|
||||||
|
last_x = self.getValue(line, "X", last_x)
|
||||||
|
last_y = self.getValue(line, "Y", last_y)
|
||||||
# Check that a layer is being printed
|
# Check that a layer is being printed
|
||||||
lines = layer.split("\n")
|
lines = layer.split("\n")
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if ";LAYER:" in line:
|
if ";LAYER:" in line:
|
||||||
index = data.index(layer)
|
|
||||||
layer += gcode_to_append
|
layer += gcode_to_append
|
||||||
|
|
||||||
data[index] = layer
|
layer += "G0 X%s Y%s\n" % (last_x, last_y)
|
||||||
|
|
||||||
|
data[idx] = layer
|
||||||
break
|
break
|
||||||
return data
|
return data
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2018 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 sys
|
import sys
|
||||||
@ -116,8 +116,9 @@ class SimulationView(CuraView):
|
|||||||
self._only_show_top_layers = bool(Application.getInstance().getPreferences().getValue("view/only_show_top_layers"))
|
self._only_show_top_layers = bool(Application.getInstance().getPreferences().getValue("view/only_show_top_layers"))
|
||||||
self._compatibility_mode = self._evaluateCompatibilityMode()
|
self._compatibility_mode = self._evaluateCompatibilityMode()
|
||||||
|
|
||||||
self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled"),
|
self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled."),
|
||||||
title = catalog.i18nc("@info:title", "Simulation View"))
|
title = catalog.i18nc("@info:title", "Simulation View"))
|
||||||
|
self._slice_first_warning_message = Message(catalog.i18nc("@info:status", "Nothing is shown because you need to slice first."), title = catalog.i18nc("@info:title", "No layer data"))
|
||||||
|
|
||||||
QtApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
|
QtApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
|
||||||
|
|
||||||
@ -149,6 +150,7 @@ class SimulationView(CuraView):
|
|||||||
if self._activity == activity:
|
if self._activity == activity:
|
||||||
return
|
return
|
||||||
self._activity = activity
|
self._activity = activity
|
||||||
|
self._updateSliceWarningVisibility()
|
||||||
self.activityChanged.emit()
|
self.activityChanged.emit()
|
||||||
|
|
||||||
def getSimulationPass(self) -> SimulationPass:
|
def getSimulationPass(self) -> SimulationPass:
|
||||||
@ -543,11 +545,13 @@ class SimulationView(CuraView):
|
|||||||
self._composite_pass.getLayerBindings().append("simulationview")
|
self._composite_pass.getLayerBindings().append("simulationview")
|
||||||
self._old_composite_shader = self._composite_pass.getCompositeShader()
|
self._old_composite_shader = self._composite_pass.getCompositeShader()
|
||||||
self._composite_pass.setCompositeShader(self._simulationview_composite_shader)
|
self._composite_pass.setCompositeShader(self._simulationview_composite_shader)
|
||||||
|
self._updateSliceWarningVisibility()
|
||||||
|
|
||||||
elif event.type == Event.ViewDeactivateEvent:
|
elif event.type == Event.ViewDeactivateEvent:
|
||||||
self._controller.getScene().getRoot().childrenChanged.disconnect(self._onSceneChanged)
|
self._controller.getScene().getRoot().childrenChanged.disconnect(self._onSceneChanged)
|
||||||
Application.getInstance().getPreferences().preferenceChanged.disconnect(self._onPreferencesChanged)
|
Application.getInstance().getPreferences().preferenceChanged.disconnect(self._onPreferencesChanged)
|
||||||
self._wireprint_warning_message.hide()
|
self._wireprint_warning_message.hide()
|
||||||
|
self._slice_first_warning_message.hide()
|
||||||
Application.getInstance().globalContainerStackChanged.disconnect(self._onGlobalStackChanged)
|
Application.getInstance().globalContainerStackChanged.disconnect(self._onGlobalStackChanged)
|
||||||
if self._global_container_stack:
|
if self._global_container_stack:
|
||||||
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
|
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
|
||||||
@ -661,6 +665,12 @@ class SimulationView(CuraView):
|
|||||||
|
|
||||||
self._updateWithPreferences()
|
self._updateWithPreferences()
|
||||||
|
|
||||||
|
def _updateSliceWarningVisibility(self):
|
||||||
|
if not self.getActivity():
|
||||||
|
self._slice_first_warning_message.show()
|
||||||
|
else:
|
||||||
|
self._slice_first_warning_message.hide()
|
||||||
|
|
||||||
|
|
||||||
class _CreateTopLayersJob(Job):
|
class _CreateTopLayersJob(Job):
|
||||||
def __init__(self, scene: "Scene", layer_number: int, solid_layers: int) -> None:
|
def __init__(self, scene: "Scene", layer_number: int, solid_layers: int) -> None:
|
||||||
|
@ -72,6 +72,7 @@ Window
|
|||||||
right: parent.right
|
right: parent.right
|
||||||
}
|
}
|
||||||
text: catalog.i18nc("@text:window", "Ultimaker Cura collects anonymous data in order to improve the print quality and user experience. Below is an example of all the data that is shared:")
|
text: catalog.i18nc("@text:window", "Ultimaker Cura collects anonymous data in order to improve the print quality and user experience. Below is an example of all the data that is shared:")
|
||||||
|
color: UM.Theme.getColor("text")
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ UM.Dialog{
|
|||||||
maximumHeight: minimumHeight
|
maximumHeight: minimumHeight
|
||||||
margin: 0
|
margin: 0
|
||||||
|
|
||||||
|
property string actionButtonText: subscribedPackagesModel.hasIncompatiblePackages && !subscribedPackagesModel.hasCompatiblePackages ? catalog.i18nc("@button", "Dismiss") : catalog.i18nc("@button", "Next")
|
||||||
|
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
id: root
|
id: root
|
||||||
@ -90,7 +92,7 @@ UM.Dialog{
|
|||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
font: UM.Theme.getFont("default")
|
font: UM.Theme.getFont("default")
|
||||||
text: catalog.i18nc("@label", "The following packages can not be installed because of incompatible Cura version:")
|
text: catalog.i18nc("@label", "The following packages can not be installed because of an incompatible Cura version:")
|
||||||
visible: subscribedPackagesModel.hasIncompatiblePackages
|
visible: subscribedPackagesModel.hasIncompatiblePackages
|
||||||
color: UM.Theme.getColor("text")
|
color: UM.Theme.getColor("text")
|
||||||
height: contentHeight + UM.Theme.getSize("default_margin").height
|
height: contentHeight + UM.Theme.getSize("default_margin").height
|
||||||
@ -125,26 +127,6 @@ 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: handler.dismissIncompatiblePackage(subscribedPackagesModel, model.package_id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,14 +134,16 @@ UM.Dialog{
|
|||||||
|
|
||||||
} // End of ScrollView
|
} // End of ScrollView
|
||||||
|
|
||||||
Cura.ActionButton
|
Cura.PrimaryButton
|
||||||
{
|
{
|
||||||
id: nextButton
|
id: nextButton
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.margins: UM.Theme.getSize("default_margin").height
|
anchors.margins: UM.Theme.getSize("default_margin").height
|
||||||
text: catalog.i18nc("@button", "Next")
|
text: actionButtonText
|
||||||
onClicked: accept()
|
onClicked: accept()
|
||||||
|
leftPadding: UM.Theme.getSize("dialog_primary_button_padding").width
|
||||||
|
rightPadding: UM.Theme.getSize("dialog_primary_button_padding").width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,12 @@
|
|||||||
import QtQuick 2.10
|
import QtQuick 2.10
|
||||||
import QtQuick.Dialogs 1.1
|
import QtQuick.Dialogs 1.1
|
||||||
import QtQuick.Window 2.2
|
import QtQuick.Window 2.2
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 2.3
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
import QtQuick.Controls.Styles 1.4
|
import QtQuick.Controls.Styles 1.4
|
||||||
|
|
||||||
// TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles
|
|
||||||
|
|
||||||
import UM 1.1 as UM
|
import UM 1.1 as UM
|
||||||
|
import Cura 1.6 as Cura
|
||||||
|
|
||||||
UM.Dialog
|
UM.Dialog
|
||||||
{
|
{
|
||||||
@ -19,50 +19,90 @@ UM.Dialog
|
|||||||
minimumHeight: UM.Theme.getSize("license_window_minimum").height
|
minimumHeight: UM.Theme.getSize("license_window_minimum").height
|
||||||
width: minimumWidth
|
width: minimumWidth
|
||||||
height: minimumHeight
|
height: minimumHeight
|
||||||
|
backgroundColor: UM.Theme.getColor("main_background")
|
||||||
|
margin: screenScaleFactor * 10
|
||||||
|
|
||||||
Item
|
ColumnLayout
|
||||||
{
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
spacing: UM.Theme.getSize("thick_margin").height
|
||||||
|
|
||||||
UM.I18nCatalog{id: catalog; name: "cura"}
|
UM.I18nCatalog{id: catalog; name: "cura"}
|
||||||
|
|
||||||
|
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: licenseHeader
|
id: licenseHeader
|
||||||
anchors.top: parent.top
|
Layout.fillWidth: true
|
||||||
anchors.left: parent.left
|
text: catalog.i18nc("@label", "You need to accept the license to install the package")
|
||||||
anchors.right: parent.right
|
color: UM.Theme.getColor("text")
|
||||||
text: licenseModel.headerText
|
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
}
|
}
|
||||||
TextArea
|
|
||||||
{
|
Row {
|
||||||
id: licenseText
|
id: packageRow
|
||||||
anchors.top: licenseHeader.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
height: childrenRect.height
|
||||||
readOnly: true
|
spacing: UM.Theme.getSize("default_margin").width
|
||||||
text: licenseModel.licenseText
|
leftPadding: UM.Theme.getSize("narrow_margin").width
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
id: icon
|
||||||
|
width: 30 * screenScaleFactor
|
||||||
|
height: width
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
source: licenseModel.iconUrl || "../../images/logobot.svg"
|
||||||
|
mipmap: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
id: packageName
|
||||||
|
text: licenseModel.packageName
|
||||||
|
color: UM.Theme.getColor("text")
|
||||||
|
font.bold: true
|
||||||
|
anchors.verticalCenter: icon.verticalCenter
|
||||||
|
height: contentHeight
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Cura.ScrollableTextArea
|
||||||
|
{
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||||
|
|
||||||
|
textArea.text: licenseModel.licenseText
|
||||||
|
textArea.readOnly: true
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
rightButtons:
|
rightButtons:
|
||||||
[
|
[
|
||||||
Button
|
Cura.PrimaryButton
|
||||||
{
|
{
|
||||||
id: acceptButton
|
leftPadding: UM.Theme.getSize("dialog_primary_button_padding").width
|
||||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
rightPadding: UM.Theme.getSize("dialog_primary_button_padding").width
|
||||||
text: catalog.i18nc("@action:button", "Accept")
|
|
||||||
|
text: licenseModel.acceptButtonText
|
||||||
onClicked: { handler.onLicenseAccepted() }
|
onClicked: { handler.onLicenseAccepted() }
|
||||||
},
|
}
|
||||||
Button
|
]
|
||||||
|
|
||||||
|
leftButtons:
|
||||||
|
[
|
||||||
|
Cura.SecondaryButton
|
||||||
{
|
{
|
||||||
id: declineButton
|
id: declineButton
|
||||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
text: licenseModel.declineButtonText
|
||||||
text: catalog.i18nc("@action:button", "Decline")
|
|
||||||
onClicked: { handler.onLicenseDeclined() }
|
onClicked: { handler.onLicenseDeclined() }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -18,3 +18,11 @@ class CloudApiModel:
|
|||||||
cloud_api_root=cloud_api_root,
|
cloud_api_root=cloud_api_root,
|
||||||
cloud_api_version=cloud_api_version,
|
cloud_api_version=cloud_api_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
## https://api.ultimaker.com/cura-packages/v1/user/packages/{package_id}
|
||||||
|
@classmethod
|
||||||
|
def userPackageUrl(cls, package_id: str) -> str:
|
||||||
|
|
||||||
|
return (CloudApiModel.api_url_user_packages + "/{package_id}").format(
|
||||||
|
package_id=package_id
|
||||||
|
)
|
||||||
|
@ -8,11 +8,12 @@ from UM import i18nCatalog
|
|||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication, ApplicationMetadata
|
||||||
from ..CloudApiModel import CloudApiModel
|
from ..CloudApiModel import CloudApiModel
|
||||||
from .SubscribedPackagesModel import SubscribedPackagesModel
|
from .SubscribedPackagesModel import SubscribedPackagesModel
|
||||||
from ..UltimakerCloudScope import UltimakerCloudScope
|
from ..UltimakerCloudScope import UltimakerCloudScope
|
||||||
|
|
||||||
|
from typing import List, Dict, Any
|
||||||
|
|
||||||
class CloudPackageChecker(QObject):
|
class CloudPackageChecker(QObject):
|
||||||
def __init__(self, application: CuraApplication) -> None:
|
def __init__(self, application: CuraApplication) -> None:
|
||||||
@ -25,12 +26,12 @@ class CloudPackageChecker(QObject):
|
|||||||
|
|
||||||
self._application.initializationFinished.connect(self._onAppInitialized)
|
self._application.initializationFinished.connect(self._onAppInitialized)
|
||||||
self._i18n_catalog = i18nCatalog("cura")
|
self._i18n_catalog = i18nCatalog("cura")
|
||||||
|
self._sdk_version = ApplicationMetadata.CuraSDKVersion
|
||||||
|
|
||||||
# This is a plugin, so most of the components required are not ready when
|
# This is a plugin, so most of the components required are not ready when
|
||||||
# this is initialized. Therefore, we wait until the application is ready.
|
# this is initialized. Therefore, we wait until the application is ready.
|
||||||
def _onAppInitialized(self) -> None:
|
def _onAppInitialized(self) -> None:
|
||||||
self._package_manager = self._application.getPackageManager()
|
self._package_manager = self._application.getPackageManager()
|
||||||
|
|
||||||
# initial check
|
# initial check
|
||||||
self._fetchUserSubscribedPackages()
|
self._fetchUserSubscribedPackages()
|
||||||
# check again whenever the login state changes
|
# check again whenever the login state changes
|
||||||
@ -38,25 +39,51 @@ class CloudPackageChecker(QObject):
|
|||||||
|
|
||||||
def _fetchUserSubscribedPackages(self) -> None:
|
def _fetchUserSubscribedPackages(self) -> None:
|
||||||
if self._application.getCuraAPI().account.isLoggedIn:
|
if self._application.getCuraAPI().account.isLoggedIn:
|
||||||
self._getUserPackages()
|
self._getUserSubscribedPackages()
|
||||||
|
|
||||||
def _handleCompatibilityData(self, json_data) -> None:
|
def _getUserSubscribedPackages(self) -> None:
|
||||||
user_subscribed_packages = [plugin["package_id"] for plugin in json_data]
|
Logger.debug("Requesting subscribed packages metadata from server.")
|
||||||
|
url = CloudApiModel.api_url_user_packages
|
||||||
|
self._application.getHttpRequestManager().get(url,
|
||||||
|
callback = self._onUserPackagesRequestFinished,
|
||||||
|
error_callback = self._onUserPackagesRequestFinished,
|
||||||
|
scope = self._scope)
|
||||||
|
|
||||||
|
def _onUserPackagesRequestFinished(self, reply: "QNetworkReply", error: Optional["QNetworkReply.NetworkError"] = None) -> None:
|
||||||
|
if error is not None or reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
|
||||||
|
Logger.log("w",
|
||||||
|
"Requesting user packages failed, response code %s while trying to connect to %s",
|
||||||
|
reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url())
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
json_data = json.loads(bytes(reply.readAll()).decode("utf-8"))
|
||||||
|
# Check for errors:
|
||||||
|
if "errors" in json_data:
|
||||||
|
for error in json_data["errors"]:
|
||||||
|
Logger.log("e", "%s", error["title"])
|
||||||
|
return
|
||||||
|
self._handleCompatibilityData(json_data["data"])
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
Logger.log("w", "Received invalid JSON for user subscribed packages from the Web Marketplace")
|
||||||
|
|
||||||
|
def _handleCompatibilityData(self, subscribed_packages_payload: List[Dict[str, Any]]) -> None:
|
||||||
|
user_subscribed_packages = [plugin["package_id"] for plugin in subscribed_packages_payload]
|
||||||
user_installed_packages = self._package_manager.getUserInstalledPackages()
|
user_installed_packages = self._package_manager.getUserInstalledPackages()
|
||||||
|
|
||||||
|
# We need to re-evaluate the dismissed packages
|
||||||
|
# (i.e. some package might got updated to the correct SDK version in the meantime,
|
||||||
|
# hence remove them from the Dismissed Incompatible list)
|
||||||
|
self._package_manager.reEvaluateDismissedPackages(subscribed_packages_payload, self._sdk_version)
|
||||||
user_dismissed_packages = self._package_manager.getDismissedPackages()
|
user_dismissed_packages = self._package_manager.getDismissedPackages()
|
||||||
if user_dismissed_packages:
|
if user_dismissed_packages:
|
||||||
user_installed_packages += user_dismissed_packages
|
user_installed_packages += user_dismissed_packages
|
||||||
# We check if there are packages installed in Cloud Marketplace but not in Cura marketplace
|
|
||||||
|
# We check if there are packages installed in Web Marketplace but not in Cura marketplace
|
||||||
package_discrepancy = list(set(user_subscribed_packages).difference(user_installed_packages))
|
package_discrepancy = list(set(user_subscribed_packages).difference(user_installed_packages))
|
||||||
|
|
||||||
self._model.setMetadata(json_data)
|
|
||||||
self._model.addDiscrepancies(package_discrepancy)
|
|
||||||
self._model.initialize()
|
|
||||||
|
|
||||||
if not self._model.hasCompatiblePackages:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if package_discrepancy:
|
if package_discrepancy:
|
||||||
|
self._model.addDiscrepancies(package_discrepancy)
|
||||||
|
self._model.initialize(subscribed_packages_payload)
|
||||||
self._handlePackageDiscrepancies()
|
self._handlePackageDiscrepancies()
|
||||||
|
|
||||||
def _handlePackageDiscrepancies(self) -> None:
|
def _handlePackageDiscrepancies(self) -> None:
|
||||||
@ -64,7 +91,6 @@ class CloudPackageChecker(QObject):
|
|||||||
sync_message = Message(self._i18n_catalog.i18nc(
|
sync_message = Message(self._i18n_catalog.i18nc(
|
||||||
"@info:generic",
|
"@info:generic",
|
||||||
"\nDo you want to sync material and software packages with your account?"),
|
"\nDo you want to sync material and software packages with your account?"),
|
||||||
lifetime=0,
|
|
||||||
title=self._i18n_catalog.i18nc("@info:title", "Changes detected from your Ultimaker account", ))
|
title=self._i18n_catalog.i18nc("@info:title", "Changes detected from your Ultimaker account", ))
|
||||||
sync_message.addAction("sync",
|
sync_message.addAction("sync",
|
||||||
name=self._i18n_catalog.i18nc("@action:button", "Sync"),
|
name=self._i18n_catalog.i18nc("@action:button", "Sync"),
|
||||||
@ -77,34 +103,3 @@ class CloudPackageChecker(QObject):
|
|||||||
def _onSyncButtonClicked(self, sync_message: Message, sync_message_action: str) -> None:
|
def _onSyncButtonClicked(self, sync_message: Message, sync_message_action: str) -> None:
|
||||||
sync_message.hide()
|
sync_message.hide()
|
||||||
self.discrepancies.emit(self._model)
|
self.discrepancies.emit(self._model)
|
||||||
|
|
||||||
def _getUserPackages(self) -> None:
|
|
||||||
Logger.log("d", "Requesting subscribed packages metadata from server.")
|
|
||||||
url = CloudApiModel.api_url_user_packages
|
|
||||||
|
|
||||||
self._application.getHttpRequestManager().get(url,
|
|
||||||
callback = self._onUserPackagesRequestFinished,
|
|
||||||
error_callback = self._onUserPackagesRequestFinished,
|
|
||||||
scope = self._scope)
|
|
||||||
|
|
||||||
def _onUserPackagesRequestFinished(self,
|
|
||||||
reply: "QNetworkReply",
|
|
||||||
error: Optional["QNetworkReply.NetworkError"] = None) -> None:
|
|
||||||
if error is not None or reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
|
|
||||||
Logger.log("w",
|
|
||||||
"Requesting user packages failed, response code %s while trying to connect to %s",
|
|
||||||
reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url())
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
json_data = json.loads(bytes(reply.readAll()).decode("utf-8"))
|
|
||||||
|
|
||||||
# Check for errors:
|
|
||||||
if "errors" in json_data:
|
|
||||||
for error in json_data["errors"]:
|
|
||||||
Logger.log("e", "%s", error["title"])
|
|
||||||
return
|
|
||||||
|
|
||||||
self._handleCompatibilityData(json_data["data"])
|
|
||||||
except json.decoder.JSONDecodeError:
|
|
||||||
Logger.log("w", "Received invalid JSON for user packages")
|
|
||||||
|
@ -1,18 +1,51 @@
|
|||||||
|
from UM.Logger import Logger
|
||||||
|
from UM.TaskManagement.HttpRequestManager import HttpRequestManager
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from ..CloudApiModel import CloudApiModel
|
from ..CloudApiModel import CloudApiModel
|
||||||
from ..UltimakerCloudScope import UltimakerCloudScope
|
from ..UltimakerCloudScope import UltimakerCloudScope
|
||||||
|
|
||||||
|
|
||||||
## Manages Cloud subscriptions. When a package is added to a user's account, the user is 'subscribed' to that package
|
|
||||||
# Whenever the user logs in on another instance of Cura, these subscriptions can be used to sync the user's plugins
|
|
||||||
class CloudPackageManager:
|
class CloudPackageManager:
|
||||||
def __init__(self, app: CuraApplication) -> None:
|
"""Manages Cloud subscriptions
|
||||||
self._request_manager = app.getHttpRequestManager()
|
|
||||||
self._scope = UltimakerCloudScope(app)
|
|
||||||
|
|
||||||
def subscribe(self, package_id: str) -> None:
|
When a package is added to a user's account, the user is 'subscribed' to that package.
|
||||||
|
Whenever the user logs in on another instance of Cura, these subscriptions can be used to sync the user's plugins
|
||||||
|
|
||||||
|
Singleton: use CloudPackageManager.getInstance() instead of CloudPackageManager()
|
||||||
|
"""
|
||||||
|
|
||||||
|
__instance = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def getInstance(cls, app: CuraApplication):
|
||||||
|
if not cls.__instance:
|
||||||
|
cls.__instance = CloudPackageManager(app)
|
||||||
|
return cls.__instance
|
||||||
|
|
||||||
|
def __init__(self, app: CuraApplication) -> None:
|
||||||
|
if self.__instance is not None:
|
||||||
|
raise RuntimeError("This is a Singleton. use getInstance()")
|
||||||
|
|
||||||
|
self._scope = UltimakerCloudScope(app) # type: UltimakerCloudScope
|
||||||
|
|
||||||
|
app.getPackageManager().packageInstalled.connect(self._onPackageInstalled)
|
||||||
|
|
||||||
|
def unsubscribe(self, package_id: str) -> None:
|
||||||
|
url = CloudApiModel.userPackageUrl(package_id)
|
||||||
|
HttpRequestManager.getInstance().delete(url = url, scope = self._scope)
|
||||||
|
|
||||||
|
def _subscribe(self, package_id: str) -> None:
|
||||||
|
"""You probably don't want to use this directly. All installed packages will be automatically subscribed."""
|
||||||
|
|
||||||
|
Logger.debug("Subscribing to {}", package_id)
|
||||||
data = "{\"data\": {\"package_id\": \"%s\", \"sdk_version\": \"%s\"}}" % (package_id, CloudApiModel.sdk_version)
|
data = "{\"data\": {\"package_id\": \"%s\", \"sdk_version\": \"%s\"}}" % (package_id, CloudApiModel.sdk_version)
|
||||||
self._request_manager.put(url=CloudApiModel.api_url_user_packages,
|
HttpRequestManager.getInstance().put(
|
||||||
|
url = CloudApiModel.api_url_user_packages,
|
||||||
data = data.encode(),
|
data = data.encode(),
|
||||||
scope = self._scope
|
scope = self._scope
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _onPackageInstalled(self, package_id: str):
|
||||||
|
if CuraApplication.getInstance().getCuraAPI().account.isLoggedIn:
|
||||||
|
# We might already be subscribed, but checking would take one extra request. Instead, simply subscribe
|
||||||
|
self._subscribe(package_id)
|
||||||
|
@ -28,13 +28,12 @@ class DiscrepanciesPresenter(QObject):
|
|||||||
assert self._dialog
|
assert self._dialog
|
||||||
self._dialog.accepted.connect(lambda: self._onConfirmClicked(model))
|
self._dialog.accepted.connect(lambda: self._onConfirmClicked(model))
|
||||||
|
|
||||||
@pyqtSlot("QVariant", str)
|
|
||||||
def dismissIncompatiblePackage(self, model: SubscribedPackagesModel, package_id: str) -> None:
|
|
||||||
model.dismissPackage(package_id) # update the model to update the view
|
|
||||||
self._package_manager.dismissPackage(package_id) # adds this package_id as dismissed in the user config file
|
|
||||||
|
|
||||||
def _onConfirmClicked(self, model: SubscribedPackagesModel) -> None:
|
def _onConfirmClicked(self, model: SubscribedPackagesModel) -> None:
|
||||||
|
# If there are incompatible packages - automatically dismiss them
|
||||||
|
if model.getIncompatiblePackages():
|
||||||
|
self._package_manager.dismissAllIncompatiblePackages(model.getIncompatiblePackages())
|
||||||
# For now, all compatible packages presented to the user should be installed.
|
# For now, all compatible packages presented to the user should be installed.
|
||||||
# Later, we might remove items for which the user unselected the package
|
# Later, we might remove items for which the user unselected the package
|
||||||
|
if model.getCompatiblePackages():
|
||||||
model.setItems(model.getCompatiblePackages())
|
model.setItems(model.getCompatiblePackages())
|
||||||
self.packageMutations.emit(model)
|
self.packageMutations.emit(model)
|
||||||
|
@ -62,7 +62,8 @@ class DownloadPresenter:
|
|||||||
"received": 0,
|
"received": 0,
|
||||||
"total": 1, # make sure this is not considered done yet. Also divByZero-safe
|
"total": 1, # make sure this is not considered done yet. Also divByZero-safe
|
||||||
"file_written": None,
|
"file_written": None,
|
||||||
"request_data": request_data
|
"request_data": request_data,
|
||||||
|
"package_model": item
|
||||||
}
|
}
|
||||||
|
|
||||||
self._started = True
|
self._started = True
|
||||||
@ -128,7 +129,14 @@ class DownloadPresenter:
|
|||||||
if not item["file_written"]:
|
if not item["file_written"]:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
success_items = {package_id : value["file_written"] for package_id, value in self._progress.items()}
|
success_items = {
|
||||||
|
package_id:
|
||||||
|
{
|
||||||
|
"package_path": value["file_written"],
|
||||||
|
"icon_url": value["package_model"]["icon_url"]
|
||||||
|
}
|
||||||
|
for package_id, value in self._progress.items()
|
||||||
|
}
|
||||||
error_items = [package_id for package_id in self._error]
|
error_items = [package_id for package_id in self._error]
|
||||||
|
|
||||||
self._progress_message.hide()
|
self._progress_message.hide()
|
||||||
|
@ -6,31 +6,52 @@ catalog = i18nCatalog("cura")
|
|||||||
|
|
||||||
# Model for the ToolboxLicenseDialog
|
# Model for the ToolboxLicenseDialog
|
||||||
class LicenseModel(QObject):
|
class LicenseModel(QObject):
|
||||||
dialogTitleChanged = pyqtSignal()
|
DEFAULT_DECLINE_BUTTON_TEXT = catalog.i18nc("@button", "Decline")
|
||||||
headerChanged = pyqtSignal()
|
ACCEPT_BUTTON_TEXT = catalog.i18nc("@button", "Agree")
|
||||||
licenseTextChanged = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
dialogTitleChanged = pyqtSignal()
|
||||||
|
packageNameChanged = pyqtSignal()
|
||||||
|
licenseTextChanged = pyqtSignal()
|
||||||
|
iconChanged = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, decline_button_text: str = DEFAULT_DECLINE_BUTTON_TEXT) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self._current_page_idx = 0
|
self._current_page_idx = 0
|
||||||
self._page_count = 1
|
self._page_count = 1
|
||||||
self._dialogTitle = ""
|
self._dialogTitle = ""
|
||||||
self._header_text = ""
|
|
||||||
self._license_text = ""
|
self._license_text = ""
|
||||||
self._package_name = ""
|
self._package_name = ""
|
||||||
|
self._icon_url = ""
|
||||||
|
self._decline_button_text = decline_button_text
|
||||||
|
|
||||||
|
@pyqtProperty(str, constant = True)
|
||||||
|
def acceptButtonText(self):
|
||||||
|
return self.ACCEPT_BUTTON_TEXT
|
||||||
|
|
||||||
|
@pyqtProperty(str, constant = True)
|
||||||
|
def declineButtonText(self):
|
||||||
|
return self._decline_button_text
|
||||||
|
|
||||||
@pyqtProperty(str, notify=dialogTitleChanged)
|
@pyqtProperty(str, notify=dialogTitleChanged)
|
||||||
def dialogTitle(self) -> str:
|
def dialogTitle(self) -> str:
|
||||||
return self._dialogTitle
|
return self._dialogTitle
|
||||||
|
|
||||||
@pyqtProperty(str, notify=headerChanged)
|
@pyqtProperty(str, notify=packageNameChanged)
|
||||||
def headerText(self) -> str:
|
def packageName(self) -> str:
|
||||||
return self._header_text
|
return self._package_name
|
||||||
|
|
||||||
def setPackageName(self, name: str) -> None:
|
def setPackageName(self, name: str) -> None:
|
||||||
self._header_text = name + ": " + catalog.i18nc("@label", "This plugin contains a license.\nYou need to accept this license to install this plugin.\nDo you agree with the terms below?")
|
self._package_name = name
|
||||||
self.headerChanged.emit()
|
self.packageNameChanged.emit()
|
||||||
|
|
||||||
|
@pyqtProperty(str, notify=iconChanged)
|
||||||
|
def iconUrl(self) -> str:
|
||||||
|
return self._icon_url
|
||||||
|
|
||||||
|
def setIconUrl(self, url: str):
|
||||||
|
self._icon_url = url
|
||||||
|
self.iconChanged.emit()
|
||||||
|
|
||||||
@pyqtProperty(str, notify=licenseTextChanged)
|
@pyqtProperty(str, notify=licenseTextChanged)
|
||||||
def licenseText(self) -> str:
|
def licenseText(self) -> str:
|
||||||
@ -50,6 +71,7 @@ class LicenseModel(QObject):
|
|||||||
self._updateDialogTitle()
|
self._updateDialogTitle()
|
||||||
|
|
||||||
def _updateDialogTitle(self):
|
def _updateDialogTitle(self):
|
||||||
self._dialogTitle = catalog.i18nc("@title:window", "Plugin License Agreement ({}/{})"
|
self._dialogTitle = catalog.i18nc("@title:window", "Plugin License Agreement")
|
||||||
.format(self._current_page_idx + 1, self._page_count))
|
if self._page_count > 1:
|
||||||
|
self._dialogTitle = self._dialogTitle + " ({}/{})".format(self._current_page_idx + 1, self._page_count)
|
||||||
self.dialogTitleChanged.emit()
|
self.dialogTitleChanged.emit()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
from typing import Dict, Optional, List
|
from collections import OrderedDict
|
||||||
|
from typing import Dict, Optional, List, Any
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtSlot
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ class LicensePresenter(QObject):
|
|||||||
|
|
||||||
def __init__(self, app: CuraApplication) -> None:
|
def __init__(self, app: CuraApplication) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self._catalog = i18nCatalog("cura")
|
||||||
self._dialog = None # type: Optional[QObject]
|
self._dialog = None # type: Optional[QObject]
|
||||||
self._package_manager = app.getPackageManager() # type: PackageManager
|
self._package_manager = app.getPackageManager() # type: PackageManager
|
||||||
# Emits List[Dict[str, [Any]] containing for example
|
# Emits List[Dict[str, [Any]] containing for example
|
||||||
@ -25,7 +27,9 @@ class LicensePresenter(QObject):
|
|||||||
|
|
||||||
self._current_package_idx = 0
|
self._current_package_idx = 0
|
||||||
self._package_models = [] # type: List[Dict]
|
self._package_models = [] # type: List[Dict]
|
||||||
self._license_model = LicenseModel() # type: LicenseModel
|
decline_button_text = self._catalog.i18nc("@button", "Decline and remove from account")
|
||||||
|
self._license_model = LicenseModel(decline_button_text=decline_button_text) # type: LicenseModel
|
||||||
|
self._page_count = 0
|
||||||
|
|
||||||
self._app = app
|
self._app = app
|
||||||
|
|
||||||
@ -34,7 +38,7 @@ class LicensePresenter(QObject):
|
|||||||
## Show a license dialog for multiple packages where users can read a license and accept or decline them
|
## Show a license dialog for multiple packages where users can read a license and accept or decline them
|
||||||
# \param plugin_path: Root directory of the Toolbox plugin
|
# \param plugin_path: Root directory of the Toolbox plugin
|
||||||
# \param packages: Dict[package id, file path]
|
# \param packages: Dict[package id, file path]
|
||||||
def present(self, plugin_path: str, packages: Dict[str, str]) -> None:
|
def present(self, plugin_path: str, packages: Dict[str, Dict[str, str]]) -> None:
|
||||||
path = os.path.join(plugin_path, self._compatibility_dialog_path)
|
path = os.path.join(plugin_path, self._compatibility_dialog_path)
|
||||||
|
|
||||||
self._initState(packages)
|
self._initState(packages)
|
||||||
@ -42,12 +46,11 @@ class LicensePresenter(QObject):
|
|||||||
if self._dialog is None:
|
if self._dialog is None:
|
||||||
|
|
||||||
context_properties = {
|
context_properties = {
|
||||||
"catalog": i18nCatalog("cura"),
|
"catalog": self._catalog,
|
||||||
"licenseModel": self._license_model,
|
"licenseModel": self._license_model,
|
||||||
"handler": self
|
"handler": self
|
||||||
}
|
}
|
||||||
self._dialog = self._app.createQmlComponent(path, context_properties)
|
self._dialog = self._app.createQmlComponent(path, context_properties)
|
||||||
self._license_model.setPageCount(len(self._package_models))
|
|
||||||
self._presentCurrentPackage()
|
self._presentCurrentPackage()
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@ -60,32 +63,41 @@ class LicensePresenter(QObject):
|
|||||||
self._package_models[self._current_package_idx]["accepted"] = False
|
self._package_models[self._current_package_idx]["accepted"] = False
|
||||||
self._checkNextPage()
|
self._checkNextPage()
|
||||||
|
|
||||||
def _initState(self, packages: Dict[str, str]) -> None:
|
def _initState(self, packages: Dict[str, Dict[str, str]]) -> None:
|
||||||
self._package_models = [
|
|
||||||
{
|
implicitly_accepted_count = 0
|
||||||
"package_id" : package_id,
|
|
||||||
"package_path" : package_path,
|
for package_id, item in packages.items():
|
||||||
"accepted" : None #: None: no answer yet
|
item["package_id"] = package_id
|
||||||
}
|
item["licence_content"] = self._package_manager.getPackageLicense(item["package_path"])
|
||||||
for package_id, package_path in packages.items()
|
if item["licence_content"] is None:
|
||||||
]
|
# Implicitly accept when there is no license
|
||||||
|
item["accepted"] = True
|
||||||
|
implicitly_accepted_count = implicitly_accepted_count + 1
|
||||||
|
self._package_models.append(item)
|
||||||
|
else:
|
||||||
|
item["accepted"] = None #: None: no answer yet
|
||||||
|
# When presenting the packages, we want to show packages which have a license first.
|
||||||
|
# In fact, we don't want to show the others at all because they are implicitly accepted
|
||||||
|
self._package_models.insert(0, item)
|
||||||
|
CuraApplication.getInstance().processEvents()
|
||||||
|
self._page_count = len(self._package_models) - implicitly_accepted_count
|
||||||
|
self._license_model.setPageCount(self._page_count)
|
||||||
|
|
||||||
|
|
||||||
def _presentCurrentPackage(self) -> None:
|
def _presentCurrentPackage(self) -> None:
|
||||||
package_model = self._package_models[self._current_package_idx]
|
package_model = self._package_models[self._current_package_idx]
|
||||||
license_content = self._package_manager.getPackageLicense(package_model["package_path"])
|
package_info = self._package_manager.getPackageInfo(package_model["package_path"])
|
||||||
if license_content is None:
|
|
||||||
# Implicitly accept when there is no license
|
|
||||||
self.onLicenseAccepted()
|
|
||||||
return
|
|
||||||
|
|
||||||
self._license_model.setCurrentPageIdx(self._current_package_idx)
|
self._license_model.setCurrentPageIdx(self._current_package_idx)
|
||||||
self._license_model.setPackageName(package_model["package_id"])
|
self._license_model.setPackageName(package_info["display_name"])
|
||||||
self._license_model.setLicenseText(license_content)
|
self._license_model.setIconUrl(package_model["icon_url"])
|
||||||
|
self._license_model.setLicenseText(package_model["licence_content"])
|
||||||
if self._dialog:
|
if self._dialog:
|
||||||
self._dialog.open() # Does nothing if already open
|
self._dialog.open() # Does nothing if already open
|
||||||
|
|
||||||
def _checkNextPage(self) -> None:
|
def _checkNextPage(self) -> None:
|
||||||
if self._current_package_idx + 1 < len(self._package_models):
|
if self._current_package_idx + 1 < self._page_count:
|
||||||
self._current_package_idx += 1
|
self._current_package_idx += 1
|
||||||
self._presentCurrentPackage()
|
self._presentCurrentPackage()
|
||||||
else:
|
else:
|
||||||
|
@ -37,27 +37,18 @@ class SubscribedPackagesModel(ListModel):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Sets the "is_compatible" to True for the given package, in memory
|
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
def addDiscrepancies(self, discrepancy: List[str]) -> None:
|
def addDiscrepancies(self, discrepancy: List[str]) -> None:
|
||||||
self._discrepancies = discrepancy
|
self._discrepancies = discrepancy
|
||||||
|
|
||||||
def getCompatiblePackages(self):
|
def getCompatiblePackages(self) -> List[Dict[str, Any]]:
|
||||||
return [x for x in self._items if x["is_compatible"]]
|
return [package for package in self._items if package["is_compatible"]]
|
||||||
|
|
||||||
def initialize(self) -> None:
|
def getIncompatiblePackages(self) -> List[str]:
|
||||||
|
return [package["package_id"] for package in self._items if not package["is_compatible"]]
|
||||||
|
|
||||||
|
def initialize(self, subscribed_packages_payload: List[Dict[str, Any]]) -> None:
|
||||||
self._items.clear()
|
self._items.clear()
|
||||||
for item in self._metadata:
|
for item in subscribed_packages_payload:
|
||||||
if item["package_id"] not in self._discrepancies:
|
if item["package_id"] not in self._discrepancies:
|
||||||
continue
|
continue
|
||||||
package = {
|
package = {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import os
|
import os
|
||||||
from typing import List, Dict, Any, cast
|
from typing import List, Dict, Any, cast
|
||||||
|
|
||||||
|
from UM import i18n_catalog
|
||||||
from UM.Extension import Extension
|
from UM.Extension import Extension
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
from UM.Message import Message
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from .CloudPackageChecker import CloudPackageChecker
|
from .CloudPackageChecker import CloudPackageChecker
|
||||||
@ -36,7 +38,8 @@ class SyncOrchestrator(Extension):
|
|||||||
self._name = "SyncOrchestrator"
|
self._name = "SyncOrchestrator"
|
||||||
|
|
||||||
self._package_manager = app.getPackageManager()
|
self._package_manager = app.getPackageManager()
|
||||||
self._cloud_package_manager = CloudPackageManager(app)
|
# Keep a reference to the CloudPackageManager. it watches for installed packages and subscribes to them
|
||||||
|
self._cloud_package_manager = CloudPackageManager.getInstance(app) # type: CloudPackageManager
|
||||||
|
|
||||||
self._checker = CloudPackageChecker(app) # type: CloudPackageChecker
|
self._checker = CloudPackageChecker(app) # type: CloudPackageChecker
|
||||||
self._checker.discrepancies.connect(self._onDiscrepancies)
|
self._checker.discrepancies.connect(self._onDiscrepancies)
|
||||||
@ -61,32 +64,37 @@ class SyncOrchestrator(Extension):
|
|||||||
self._download_presenter.download(mutations)
|
self._download_presenter.download(mutations)
|
||||||
|
|
||||||
## Called when a set of packages have finished downloading
|
## Called when a set of packages have finished downloading
|
||||||
# \param success_items: Dict[package_id, file_path]
|
# \param success_items: Dict[package_id, Dict[str, str]]
|
||||||
# \param error_items: List[package_id]
|
# \param error_items: List[package_id]
|
||||||
def _onDownloadFinished(self, success_items: Dict[str, str], error_items: List[str]) -> None:
|
def _onDownloadFinished(self, success_items: Dict[str, Dict[str, str]], error_items: List[str]) -> None:
|
||||||
# todo handle error items
|
if error_items:
|
||||||
|
message = i18n_catalog.i18nc("@info:generic", "{} plugins failed to download".format(len(error_items)))
|
||||||
|
self._showErrorMessage(message)
|
||||||
|
|
||||||
plugin_path = cast(str, PluginRegistry.getInstance().getPluginPath(self.getPluginId()))
|
plugin_path = cast(str, PluginRegistry.getInstance().getPluginPath(self.getPluginId()))
|
||||||
self._license_presenter.present(plugin_path, success_items)
|
self._license_presenter.present(plugin_path, success_items)
|
||||||
|
|
||||||
# Called when user has accepted / declined all licenses for the downloaded packages
|
# Called when user has accepted / declined all licenses for the downloaded packages
|
||||||
def _onLicenseAnswers(self, answers: List[Dict[str, Any]]) -> None:
|
def _onLicenseAnswers(self, answers: List[Dict[str, Any]]) -> None:
|
||||||
Logger.debug("Got license answers: {}", answers)
|
|
||||||
|
|
||||||
has_changes = False # True when at least one package is installed
|
has_changes = False # True when at least one package is installed
|
||||||
|
|
||||||
for item in answers:
|
for item in answers:
|
||||||
if item["accepted"]:
|
if item["accepted"]:
|
||||||
# install and subscribe packages
|
# install and subscribe packages
|
||||||
if not self._package_manager.installPackage(item["package_path"]):
|
if not self._package_manager.installPackage(item["package_path"]):
|
||||||
Logger.error("could not install {}".format(item["package_id"]))
|
message = "Could not install {}".format(item["package_id"])
|
||||||
|
self._showErrorMessage(message)
|
||||||
continue
|
continue
|
||||||
self._cloud_package_manager.subscribe(item["package_id"])
|
|
||||||
has_changes = True
|
has_changes = True
|
||||||
else:
|
else:
|
||||||
# todo unsubscribe declined packages
|
self._cloud_package_manager.unsubscribe(item["package_id"])
|
||||||
pass
|
|
||||||
# delete temp file
|
# delete temp file
|
||||||
os.remove(item["package_path"])
|
os.remove(item["package_path"])
|
||||||
|
|
||||||
if has_changes:
|
if has_changes:
|
||||||
self._restart_presenter.present()
|
self._restart_presenter.present()
|
||||||
|
|
||||||
|
## Logs an error and shows it to the user
|
||||||
|
def _showErrorMessage(self, text: str):
|
||||||
|
Logger.error(text)
|
||||||
|
Message(text, lifetime=0).show()
|
||||||
|
@ -21,7 +21,6 @@ from cura.Machines.ContainerTree import ContainerTree
|
|||||||
|
|
||||||
from .CloudApiModel import CloudApiModel
|
from .CloudApiModel import CloudApiModel
|
||||||
from .AuthorsModel import AuthorsModel
|
from .AuthorsModel import AuthorsModel
|
||||||
from .CloudSync.CloudPackageManager import CloudPackageManager
|
|
||||||
from .CloudSync.LicenseModel import LicenseModel
|
from .CloudSync.LicenseModel import LicenseModel
|
||||||
from .PackagesModel import PackagesModel
|
from .PackagesModel import PackagesModel
|
||||||
from .UltimakerCloudScope import UltimakerCloudScope
|
from .UltimakerCloudScope import UltimakerCloudScope
|
||||||
@ -44,7 +43,6 @@ class Toolbox(QObject, Extension):
|
|||||||
self._sdk_version = ApplicationMetadata.CuraSDKVersion # type: Union[str, int]
|
self._sdk_version = ApplicationMetadata.CuraSDKVersion # type: Union[str, int]
|
||||||
|
|
||||||
# Network:
|
# Network:
|
||||||
self._cloud_package_manager = CloudPackageManager(application) # type: CloudPackageManager
|
|
||||||
self._download_request_data = None # type: Optional[HttpRequestData]
|
self._download_request_data = None # type: Optional[HttpRequestData]
|
||||||
self._download_progress = 0 # type: float
|
self._download_progress = 0 # type: float
|
||||||
self._is_downloading = False # type: bool
|
self._is_downloading = False # type: bool
|
||||||
@ -147,17 +145,14 @@ class Toolbox(QObject, Extension):
|
|||||||
|
|
||||||
self._application.getHttpRequestManager().put(url, data = data.encode(), scope = self._scope)
|
self._application.getHttpRequestManager().put(url, data = data.encode(), scope = self._scope)
|
||||||
|
|
||||||
@pyqtSlot(str)
|
|
||||||
def subscribe(self, package_id: str) -> None:
|
|
||||||
self._cloud_package_manager.subscribe(package_id)
|
|
||||||
|
|
||||||
def getLicenseDialogPluginFileLocation(self) -> str:
|
def getLicenseDialogPluginFileLocation(self) -> str:
|
||||||
return self._license_dialog_plugin_file_location
|
return self._license_dialog_plugin_file_location
|
||||||
|
|
||||||
def openLicenseDialog(self, plugin_name: str, license_content: str, plugin_file_location: str) -> None:
|
def openLicenseDialog(self, plugin_name: str, license_content: str, plugin_file_location: str, icon_url: str) -> None:
|
||||||
# Set page 1/1 when opening the dialog for a single package
|
# Set page 1/1 when opening the dialog for a single package
|
||||||
self._license_model.setCurrentPageIdx(0)
|
self._license_model.setCurrentPageIdx(0)
|
||||||
self._license_model.setPageCount(1)
|
self._license_model.setPageCount(1)
|
||||||
|
self._license_model.setIconUrl(icon_url)
|
||||||
|
|
||||||
self._license_model.setPackageName(plugin_name)
|
self._license_model.setPackageName(plugin_name)
|
||||||
self._license_model.setLicenseText(license_content)
|
self._license_model.setLicenseText(license_content)
|
||||||
@ -376,7 +371,6 @@ class Toolbox(QObject, Extension):
|
|||||||
def onLicenseAccepted(self):
|
def onLicenseAccepted(self):
|
||||||
self.closeLicenseDialog.emit()
|
self.closeLicenseDialog.emit()
|
||||||
package_id = self.install(self.getLicenseDialogPluginFileLocation())
|
package_id = self.install(self.getLicenseDialogPluginFileLocation())
|
||||||
self.subscribe(package_id)
|
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@ -670,14 +664,16 @@ class Toolbox(QObject, Extension):
|
|||||||
return
|
return
|
||||||
|
|
||||||
license_content = self._package_manager.getPackageLicense(file_path)
|
license_content = self._package_manager.getPackageLicense(file_path)
|
||||||
|
package_id = package_info["package_id"]
|
||||||
if license_content is not None:
|
if license_content is not None:
|
||||||
self.openLicenseDialog(package_info["package_id"], license_content, file_path)
|
# get the icon url for package_id, make sure the result is a string, never None
|
||||||
|
icon_url = next((x["icon_url"] for x in self.packagesModel.items if x["id"] == package_id), None) or ""
|
||||||
|
self.openLicenseDialog(package_info["display_name"], license_content, file_path, icon_url)
|
||||||
return
|
return
|
||||||
|
|
||||||
package_id = self.install(file_path)
|
installed_id = self.install(file_path)
|
||||||
if package_id != package_info["package_id"]:
|
if installed_id != package_id:
|
||||||
Logger.error("Installed package {} does not match {}".format(package_id, package_info["package_id"]))
|
Logger.error("Installed package {} does not match {}".format(installed_id, package_id))
|
||||||
self.subscribe(package_id)
|
|
||||||
|
|
||||||
# Getter & Setters for Properties:
|
# Getter & Setters for Properties:
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
@ -699,14 +695,14 @@ class Toolbox(QObject, Extension):
|
|||||||
def isDownloading(self) -> bool:
|
def isDownloading(self) -> bool:
|
||||||
return self._is_downloading
|
return self._is_downloading
|
||||||
|
|
||||||
def setActivePackage(self, package: Dict[str, Any]) -> None:
|
def setActivePackage(self, package: QObject) -> None:
|
||||||
if self._active_package != package:
|
if self._active_package != package:
|
||||||
self._active_package = package
|
self._active_package = package
|
||||||
self.activePackageChanged.emit()
|
self.activePackageChanged.emit()
|
||||||
|
|
||||||
## The active package is the package that is currently being downloaded
|
## The active package is the package that is currently being downloaded
|
||||||
@pyqtProperty(QObject, fset = setActivePackage, notify = activePackageChanged)
|
@pyqtProperty(QObject, fset = setActivePackage, notify = activePackageChanged)
|
||||||
def activePackage(self) -> Optional[Dict[str, Any]]:
|
def activePackage(self) -> Optional[QObject]:
|
||||||
return self._active_package
|
return self._active_package
|
||||||
|
|
||||||
def setViewCategory(self, category: str = "plugin") -> None:
|
def setViewCategory(self, category: str = "plugin") -> None:
|
||||||
|
@ -6,6 +6,9 @@ from cura.API import Account
|
|||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
|
|
||||||
|
## Add a Authorization header to the request for Ultimaker Cloud Api requests.
|
||||||
|
# When the user is not logged in or a token is not available, a warning will be logged
|
||||||
|
# Also add the user agent headers (see DefaultUserAgentScope)
|
||||||
class UltimakerCloudScope(DefaultUserAgentScope):
|
class UltimakerCloudScope(DefaultUserAgentScope):
|
||||||
def __init__(self, application: CuraApplication):
|
def __init__(self, application: CuraApplication):
|
||||||
super().__init__(application)
|
super().__init__(application)
|
||||||
|
@ -848,6 +848,23 @@
|
|||||||
"website": "https://ultimaker.com"
|
"website": "https://ultimaker.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"VersionUpgrade44to45": {
|
||||||
|
"package_info": {
|
||||||
|
"package_id": "VersionUpgrade44to45",
|
||||||
|
"package_type": "plugin",
|
||||||
|
"display_name": "Version Upgrade 4.4 to 4.5",
|
||||||
|
"description": "Upgrades configurations from Cura 4.4 to Cura 4.5.",
|
||||||
|
"package_version": "1.0.0",
|
||||||
|
"sdk_version": "7.0.0",
|
||||||
|
"website": "https://ultimaker.com",
|
||||||
|
"author": {
|
||||||
|
"author_id": "UltimakerPackages",
|
||||||
|
"display_name": "Ultimaker B.V.",
|
||||||
|
"email": "plugins@ultimaker.com",
|
||||||
|
"website": "https://ultimaker.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"X3DReader": {
|
"X3DReader": {
|
||||||
"package_info": {
|
"package_info": {
|
||||||
|
@ -2122,6 +2122,7 @@
|
|||||||
"default_value": 210,
|
"default_value": 210,
|
||||||
"minimum_value_warning": "0",
|
"minimum_value_warning": "0",
|
||||||
"maximum_value_warning": "285",
|
"maximum_value_warning": "285",
|
||||||
|
"maximum_value": "365",
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"settable_per_extruder": true,
|
"settable_per_extruder": true,
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
@ -2153,6 +2154,7 @@
|
|||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "0",
|
"minimum_value_warning": "0",
|
||||||
"maximum_value_warning": "285",
|
"maximum_value_warning": "285",
|
||||||
|
"maximum_value": "365",
|
||||||
"enabled": "machine_nozzle_temp_enabled and not (material_flow_dependent_temperature)",
|
"enabled": "machine_nozzle_temp_enabled and not (material_flow_dependent_temperature)",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
@ -2168,6 +2170,7 @@
|
|||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "0",
|
"minimum_value_warning": "0",
|
||||||
"maximum_value_warning": "285",
|
"maximum_value_warning": "285",
|
||||||
|
"maximum_value": "365",
|
||||||
"enabled": "machine_nozzle_temp_enabled",
|
"enabled": "machine_nozzle_temp_enabled",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
@ -2183,6 +2186,7 @@
|
|||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "material_standby_temperature",
|
"minimum_value_warning": "material_standby_temperature",
|
||||||
"maximum_value_warning": "material_print_temperature",
|
"maximum_value_warning": "material_print_temperature",
|
||||||
|
"maximum_value": "365",
|
||||||
"enabled": "machine_nozzle_temp_enabled and not machine_extruders_share_heater",
|
"enabled": "machine_nozzle_temp_enabled and not machine_extruders_share_heater",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
@ -2198,6 +2202,7 @@
|
|||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "material_standby_temperature",
|
"minimum_value_warning": "material_standby_temperature",
|
||||||
"maximum_value_warning": "material_print_temperature",
|
"maximum_value_warning": "material_print_temperature",
|
||||||
|
"maximum_value": "365",
|
||||||
"enabled": "machine_nozzle_temp_enabled and not machine_extruders_share_heater",
|
"enabled": "machine_nozzle_temp_enabled and not machine_extruders_share_heater",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
@ -2227,6 +2232,7 @@
|
|||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "build_volume_temperature",
|
"minimum_value_warning": "build_volume_temperature",
|
||||||
"maximum_value_warning": "130",
|
"maximum_value_warning": "130",
|
||||||
|
"maximum_value": "200",
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
@ -2244,6 +2250,7 @@
|
|||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "build_volume_temperature",
|
"minimum_value_warning": "build_volume_temperature",
|
||||||
"maximum_value_warning": "130",
|
"maximum_value_warning": "130",
|
||||||
|
"maximum_value": "200",
|
||||||
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"",
|
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
@ -2261,6 +2268,7 @@
|
|||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "max(build_volume_temperature, max(extruderValues('material_bed_temperature')))",
|
"minimum_value_warning": "max(build_volume_temperature, max(extruderValues('material_bed_temperature')))",
|
||||||
"maximum_value_warning": "130",
|
"maximum_value_warning": "130",
|
||||||
|
"maximum_value": "200",
|
||||||
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"",
|
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
@ -2377,6 +2385,7 @@
|
|||||||
"enabled": false,
|
"enabled": false,
|
||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"maximum_value_warning": "300",
|
"maximum_value_warning": "300",
|
||||||
|
"maximum_value": "365",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
},
|
},
|
||||||
@ -2415,6 +2424,7 @@
|
|||||||
"default_value": 50,
|
"default_value": 50,
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
|
"maximum_value": "365",
|
||||||
"maximum_value_warning": "300",
|
"maximum_value_warning": "300",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
@ -2691,6 +2701,7 @@
|
|||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "0",
|
"minimum_value_warning": "0",
|
||||||
"maximum_value_warning": "260",
|
"maximum_value_warning": "260",
|
||||||
|
"maximum_value": "365",
|
||||||
"enabled": "extruders_enabled_count > 1 and machine_nozzle_temp_enabled",
|
"enabled": "extruders_enabled_count > 1 and machine_nozzle_temp_enabled",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
@ -5688,7 +5699,7 @@
|
|||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"enabled": "resolveOrValue('prime_tower_enable')",
|
"enabled": "resolveOrValue('prime_tower_enable')",
|
||||||
"default_value": 200,
|
"default_value": 200,
|
||||||
"value": "machine_width - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' or (prime_tower_brim_enable and adhesion_type != 'raft') else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - 1",
|
"value": "machine_width - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' or (prime_tower_brim_enable and adhesion_type != 'raft') else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - max(map(abs, extruderValues('machine_nozzle_offset_x'))) - 1",
|
||||||
"maximum_value": "machine_width / 2 if machine_center_is_zero else machine_width",
|
"maximum_value": "machine_width / 2 if machine_center_is_zero else machine_width",
|
||||||
"minimum_value": "resolveOrValue('prime_tower_size') - machine_width / 2 if machine_center_is_zero else resolveOrValue('prime_tower_size')",
|
"minimum_value": "resolveOrValue('prime_tower_size') - machine_width / 2 if machine_center_is_zero else resolveOrValue('prime_tower_size')",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
@ -5702,7 +5713,7 @@
|
|||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"enabled": "resolveOrValue('prime_tower_enable')",
|
"enabled": "resolveOrValue('prime_tower_enable')",
|
||||||
"default_value": 200,
|
"default_value": 200,
|
||||||
"value": "machine_depth - prime_tower_size - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' or (prime_tower_brim_enable and adhesion_type != 'raft') else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - 1",
|
"value": "machine_depth - prime_tower_size - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' or (prime_tower_brim_enable and adhesion_type != 'raft') else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - max(map(abs, extruderValues('machine_nozzle_offset_y'))) - 1",
|
||||||
"maximum_value": "machine_depth / 2 - resolveOrValue('prime_tower_size') if machine_center_is_zero else machine_depth - resolveOrValue('prime_tower_size')",
|
"maximum_value": "machine_depth / 2 - resolveOrValue('prime_tower_size') if machine_center_is_zero else machine_depth - resolveOrValue('prime_tower_size')",
|
||||||
"minimum_value": "machine_depth / -2 if machine_center_is_zero else 0",
|
"minimum_value": "machine_depth / -2 if machine_center_is_zero else 0",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
@ -5984,7 +5995,7 @@
|
|||||||
"print_sequence":
|
"print_sequence":
|
||||||
{
|
{
|
||||||
"label": "Print Sequence",
|
"label": "Print Sequence",
|
||||||
"description": "Whether to print all models one layer at a time or to wait for one model to finish, before moving on to the next. One at a time mode is only possible if all models are separated in such a way that the whole print head can move in between and all models are lower than the distance between the nozzle and the X/Y axes.",
|
"description": "Whether to print all models one layer at a time or to wait for one model to finish, before moving on to the next. One at a time mode is possible if a) only one extruder is enabled and b) all models are separated in such a way that the whole print head can move in between and all models are lower than the distance between the nozzle and the X/Y axes. ",
|
||||||
"type": "enum",
|
"type": "enum",
|
||||||
"options":
|
"options":
|
||||||
{
|
{
|
||||||
@ -6666,6 +6677,16 @@
|
|||||||
"limit_to_extruder": "wall_0_extruder_nr",
|
"limit_to_extruder": "wall_0_extruder_nr",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
},
|
},
|
||||||
|
"magic_fuzzy_skin_outside_only":
|
||||||
|
{
|
||||||
|
"label": "Fuzzy Skin Outside Only",
|
||||||
|
"description": "Jitter only the parts' outlines and not the parts' holes.",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": false,
|
||||||
|
"enabled": "magic_fuzzy_skin_enabled",
|
||||||
|
"limit_to_extruder": "wall_0_extruder_nr",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
"magic_fuzzy_skin_thickness":
|
"magic_fuzzy_skin_thickness":
|
||||||
{
|
{
|
||||||
"label": "Fuzzy Skin Thickness",
|
"label": "Fuzzy Skin Thickness",
|
||||||
|
57
resources/definitions/geeetech_A10.def.json
Normal file
57
resources/definitions/geeetech_A10.def.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Geeetech A10",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Amit L",
|
||||||
|
"manufacturer": "Geeetech",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"has_materials": true,
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "geeetech_A10_1"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "Geeetech A10" },
|
||||||
|
"machine_width": {
|
||||||
|
"default_value": 220
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"default_value": 220
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"default_value": 260
|
||||||
|
}, "machine_center_is_zero": {
|
||||||
|
"default_value": false
|
||||||
|
},
|
||||||
|
"layer_height": { "default_value": 0.1 },
|
||||||
|
"layer_height_0": { "default_value": 0.15 },
|
||||||
|
"retraction_amount": { "default_value": 0.8 },
|
||||||
|
"retraction_speed": { "default_value": 35 },
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"machine_head_with_fans_polygon": { "default_value": [[-31,31],[34,31],[34,-40],[-31,-40]] },
|
||||||
|
"gantry_height": { "value": "28" },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 12 },
|
||||||
|
"machine_max_feedrate_e": { "default_value": 120 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 500 },
|
||||||
|
"machine_acceleration": { "default_value": 1000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 10 },
|
||||||
|
"machine_max_jerk_z": { "default_value": 0.2 },
|
||||||
|
"machine_max_jerk_e": { "default_value": 2.5 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G28 \nG1 Z15 F300\nM107\nG90\nM82\nM104 S215\nM140 S55\nG92 E0\nM109 S215\nM107\nG0 X10 Y20 F6000\nG1 Z0.8\nG1 F300 X180 E40\nG1 F1200 Z2\nG92 E0\nG28"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "G91\nG1 E-1\nG0 X0 Y200\nM104 S0\nG90\nG92 E0\nM140 S0\nM84\nM104 S0\nM140 S0\nM84"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": {
|
||||||
|
"default_value": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
58
resources/definitions/geeetech_A10M.def.json
Normal file
58
resources/definitions/geeetech_A10M.def.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Geeetech A10M",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Amit L",
|
||||||
|
"manufacturer": "Geeetech",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"has_materials": true,
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "geeetech_A10M_1",
|
||||||
|
"1": "geeetech_A10M_2"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "Geeetech A10M" },
|
||||||
|
"machine_width": {
|
||||||
|
"default_value": 220
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"default_value": 220
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"default_value": 260
|
||||||
|
}, "machine_center_is_zero": {
|
||||||
|
"default_value": false
|
||||||
|
},
|
||||||
|
"layer_height": { "default_value": 0.1 },
|
||||||
|
"layer_height_0": { "default_value": 0.15 },
|
||||||
|
"retraction_amount": { "default_value": 0.8 },
|
||||||
|
"retraction_speed": { "default_value": 35 },
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"machine_head_with_fans_polygon": { "default_value": [[-31,31],[34,31],[34,-40],[-31,-40]] },
|
||||||
|
"gantry_height": { "value": "28" },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 12 },
|
||||||
|
"machine_max_feedrate_e": { "default_value": 120 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 500 },
|
||||||
|
"machine_acceleration": { "default_value": 1000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 10 },
|
||||||
|
"machine_max_jerk_z": { "default_value": 0.2 },
|
||||||
|
"machine_max_jerk_e": { "default_value": 2.5 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G28 \nG1 Z15 F300\nM107\nG90\nM82\nM104 S215\nM140 S55\nG92 E0\nM109 S215\nM107\nM163 S0 P0.50\nM163 S1 P0.50\nM164 S4\nG0 X10 Y20 F6000\nG1 Z0.8\nG1 F300 X180 E40\nG1 F1200 Z2\nG92 E0\nG28"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "G91\nG1 E-1\nG0 X0 Y200\nM104 S0\nG90\nG92 E0\nM140 S0\nM84\nM104 S0\nM140 S0\nM84"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": {
|
||||||
|
"default_value": 2
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
59
resources/definitions/geeetech_A10T.def.json
Normal file
59
resources/definitions/geeetech_A10T.def.json
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Geeetech A10T",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Amit L",
|
||||||
|
"manufacturer": "Geeetech",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"has_materials": true,
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "geeetech_A10T_1",
|
||||||
|
"1": "geeetech_A10T_2",
|
||||||
|
"2": "geeetech_A10T_3"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "Geeetech A10T" },
|
||||||
|
"machine_width": {
|
||||||
|
"default_value": 220
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"default_value": 220
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"default_value": 260
|
||||||
|
}, "machine_center_is_zero": {
|
||||||
|
"default_value": false
|
||||||
|
},
|
||||||
|
"layer_height": { "default_value": 0.1 },
|
||||||
|
"layer_height_0": { "default_value": 0.15 },
|
||||||
|
"retraction_amount": { "default_value": 0.8 },
|
||||||
|
"retraction_speed": { "default_value": 35 },
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"machine_head_with_fans_polygon": { "default_value": [[-31,31],[34,31],[34,-40],[-31,-40]] },
|
||||||
|
"gantry_height": { "value": "28" },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 12 },
|
||||||
|
"machine_max_feedrate_e": { "default_value": 120 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 500 },
|
||||||
|
"machine_acceleration": { "default_value": 1000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 10 },
|
||||||
|
"machine_max_jerk_z": { "default_value": 0.2 },
|
||||||
|
"machine_max_jerk_e": { "default_value": 2.5 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G28 \nG1 Z15 F300\nM107\nG90\nM82\nM104 S215\nM140 S55\nG92 E0\nM109 S215\nM107\nM163 S0 P0.33\nM163 S1 P0.33\nM163 S2 P0.33\nM164 S4\nG0 X10 Y20 F6000\nG1 Z0.8\nG1 F300 X180 E40\nG1 F1200 Z2\nG92 E0\nG28"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "G91\nG1 E-1\nG0 X0 Y200\nM104 S0\nG90\nG92 E0\nM140 S0\nM84\nM104 S0\nM140 S0\nM84"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": {
|
||||||
|
"default_value": 3
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
57
resources/definitions/geeetech_A20.def.json
Normal file
57
resources/definitions/geeetech_A20.def.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Geeetech A20",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Amit L",
|
||||||
|
"manufacturer": "Geeetech",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"has_materials": true,
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "geeetech_A20_1"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "Geeetech A20" },
|
||||||
|
"machine_width": {
|
||||||
|
"default_value": 250
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"default_value": 250
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"default_value": 250
|
||||||
|
}, "machine_center_is_zero": {
|
||||||
|
"default_value": false
|
||||||
|
},
|
||||||
|
"layer_height": { "default_value": 0.1 },
|
||||||
|
"layer_height_0": { "default_value": 0.15 },
|
||||||
|
"retraction_amount": { "default_value": 0.8 },
|
||||||
|
"retraction_speed": { "default_value": 35 },
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"machine_head_with_fans_polygon": { "default_value": [[-31,31],[34,31],[34,-40],[-31,-40]] },
|
||||||
|
"gantry_height": { "value": "28" },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 12 },
|
||||||
|
"machine_max_feedrate_e": { "default_value": 120 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 500 },
|
||||||
|
"machine_acceleration": { "default_value": 1000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 10 },
|
||||||
|
"machine_max_jerk_z": { "default_value": 0.2 },
|
||||||
|
"machine_max_jerk_e": { "default_value": 2.5 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G28 \nG1 Z15 F300\nM107\nG90\nM82\nM104 S215\nM140 S55\nG92 E0\nM109 S215\nM107\nG0 X10 Y20 F6000\nG1 Z0.8\nG1 F300 X200 E40\nG1 F1200 Z2\nG92 E0\nG28"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "G91\nG1 E-1\nG0 X0 Y200\nM104 S0\nG90\nG92 E0\nM140 S0\nM84\nM104 S0\nM140 S0\nM84"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": {
|
||||||
|
"default_value": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
58
resources/definitions/geeetech_A20M.def.json
Normal file
58
resources/definitions/geeetech_A20M.def.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Geeetech A20M",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Amit L",
|
||||||
|
"manufacturer": "Geeetech",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"has_materials": true,
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "geeetech_A20M_1",
|
||||||
|
"1": "geeetech_A20M_2"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "Geeetech A20M" },
|
||||||
|
"machine_width": {
|
||||||
|
"default_value": 250
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"default_value": 250
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"default_value": 250
|
||||||
|
}, "machine_center_is_zero": {
|
||||||
|
"default_value": false
|
||||||
|
},
|
||||||
|
"layer_height": { "default_value": 0.1 },
|
||||||
|
"layer_height_0": { "default_value": 0.15 },
|
||||||
|
"retraction_amount": { "default_value": 0.8 },
|
||||||
|
"retraction_speed": { "default_value": 35 },
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"machine_head_with_fans_polygon": { "default_value": [[-31,31],[34,31],[34,-40],[-31,-40]] },
|
||||||
|
"gantry_height": { "value": "28" },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 12 },
|
||||||
|
"machine_max_feedrate_e": { "default_value": 120 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 500 },
|
||||||
|
"machine_acceleration": { "default_value": 1000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 10 },
|
||||||
|
"machine_max_jerk_z": { "default_value": 0.2 },
|
||||||
|
"machine_max_jerk_e": { "default_value": 2.5 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G28 \nG1 Z15 F300\nM107\nG90\nM82\nM104 S215\nM140 S55\nG92 E0\nM109 S215\nM107\nM163 S0 P0.50\nM163 S1 P0.50\nM164 S4\nG0 X10 Y20 F6000\nG1 Z0.8\nG1 F300 X200 E40\nG1 F1200 Z2\nG92 E0\nG28"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "G91\nG1 E-1\nG0 X0 Y200\nM104 S0\nG90\nG92 E0\nM140 S0\nM84\nM104 S0\nM140 S0\nM84"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": {
|
||||||
|
"default_value": 2
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
59
resources/definitions/geeetech_A20T.def.json
Normal file
59
resources/definitions/geeetech_A20T.def.json
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Geeetech A20T",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Amit L",
|
||||||
|
"manufacturer": "Geeetech",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"has_materials": true,
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "geeetech_A20T_1",
|
||||||
|
"1": "geeetech_A20T_2",
|
||||||
|
"2": "geeetech_A20T_3"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "Geeetech A20T" },
|
||||||
|
"machine_width": {
|
||||||
|
"default_value": 250
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"default_value": 250
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"default_value": 250
|
||||||
|
}, "machine_center_is_zero": {
|
||||||
|
"default_value": false
|
||||||
|
},
|
||||||
|
"layer_height": { "default_value": 0.1 },
|
||||||
|
"layer_height_0": { "default_value": 0.15 },
|
||||||
|
"retraction_amount": { "default_value": 0.8 },
|
||||||
|
"retraction_speed": { "default_value": 35 },
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"machine_head_with_fans_polygon": { "default_value": [[-31,31],[34,31],[34,-40],[-31,-40]] },
|
||||||
|
"gantry_height": { "value": "28" },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 12 },
|
||||||
|
"machine_max_feedrate_e": { "default_value": 120 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 500 },
|
||||||
|
"machine_acceleration": { "default_value": 1000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 10 },
|
||||||
|
"machine_max_jerk_z": { "default_value": 0.2 },
|
||||||
|
"machine_max_jerk_e": { "default_value": 2.5 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G28 \nG1 Z15 F300\nM107\nG90\nM82\nM104 S215\nM140 S55\nG92 E0\nM109 S215\nM107\nM163 S0 P0.33\nM163 S1 P0.33\nM163 S2 P0.33\nM164 S4\nG0 X10 Y20 F6000\nG1 Z0.8\nG1 F300 X200 E40\nG1 F1200 Z2\nG92 E0\nG28"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "G91\nG1 E-1\nG0 X0 Y200\nM104 S0\nG90\nG92 E0\nM140 S0\nM84\nM104 S0\nM140 S0\nM84"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": {
|
||||||
|
"default_value": 3
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
96
resources/definitions/makeit_pro_mx.def.json
Normal file
96
resources/definitions/makeit_pro_mx.def.json
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "MAKEiT Pro-MX",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "unknown",
|
||||||
|
"manufacturer": "MAKEiT 3D",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"has_materials": false,
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "makeit_mx_dual_1st",
|
||||||
|
"1": "makeit_mx_dual_2nd"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "MAKEiT Pro-MX" },
|
||||||
|
"machine_width": {
|
||||||
|
"default_value": 200
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"default_value": 330
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"default_value": 240
|
||||||
|
},
|
||||||
|
"machine_center_is_zero": {
|
||||||
|
"default_value": false
|
||||||
|
},
|
||||||
|
"machine_head_with_fans_polygon":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[ -200, 240 ],
|
||||||
|
[ -200, -32 ],
|
||||||
|
[ 200, 240 ],
|
||||||
|
[ 200, -32 ]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gantry_height": {
|
||||||
|
"value": "200"
|
||||||
|
},
|
||||||
|
"machine_use_extruder_offset_to_offset_coords": {
|
||||||
|
"default_value": true
|
||||||
|
},
|
||||||
|
"machine_gcode_flavor": {
|
||||||
|
"default_value": "RepRap (Marlin/Sprinter)"
|
||||||
|
},
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nG92 E0 ;zero the extruded length\nG28 ;home\nG1 F200 E30 ;extrude 30 mm of feed stock\nG92 E0 ;zero the extruded length\nG1 E-5 ;retract 5 mm\nG28 SC ;Do homeing, clean nozzles and let printer to know that printing started\nG92 X-6 ;Sets Curas checker board to match printers heated bed coordinates\nG1 F{speed_travel}\nM117 Printing..."
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "M104 T0 S0 ;1st extruder heater off\nM104 T1 S0 ;2nd extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-5 F9000 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+5 X+20 Y+20 F9000 ;move Z up a bit\nM117 MAKEiT Pro@Done\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning\nM81"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": {
|
||||||
|
"default_value": 2
|
||||||
|
},
|
||||||
|
"print_sequence": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"prime_tower_position_x": {
|
||||||
|
"value": "185"
|
||||||
|
},
|
||||||
|
"prime_tower_position_y": {
|
||||||
|
"value": "160"
|
||||||
|
},
|
||||||
|
"layer_height": {
|
||||||
|
"default_value": 0.2
|
||||||
|
},
|
||||||
|
"retraction_speed": {
|
||||||
|
"default_value": 180
|
||||||
|
},
|
||||||
|
"infill_sparse_density": {
|
||||||
|
"default_value": 20
|
||||||
|
},
|
||||||
|
"retraction_amount": {
|
||||||
|
"default_value": 6
|
||||||
|
},
|
||||||
|
"speed_print": {
|
||||||
|
"default_value": 60
|
||||||
|
},
|
||||||
|
"wall_thickness": {
|
||||||
|
"default_value": 1.2
|
||||||
|
},
|
||||||
|
"cool_min_layer_time_fan_speed_max": {
|
||||||
|
"default_value": 5
|
||||||
|
},
|
||||||
|
"adhesion_type": {
|
||||||
|
"default_value": "skirt"
|
||||||
|
},
|
||||||
|
"machine_heated_bed": {
|
||||||
|
"default_value": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
resources/definitions/mp_mini_delta.def.json
Normal file
76
resources/definitions/mp_mini_delta.def.json
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "MP Mini Delta",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"author": "MPMD Facebook Group",
|
||||||
|
"manufacturer": "Monoprice",
|
||||||
|
"category": "Other",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"platform": "mp_mini_delta_platform.stl",
|
||||||
|
"supports_usb_connection": true,
|
||||||
|
"has_machine_quality": false,
|
||||||
|
"visible": true,
|
||||||
|
"platform_offset": [0, 0, 0],
|
||||||
|
"has_materials": true,
|
||||||
|
"has_variants": false,
|
||||||
|
"has_machine_materials": false,
|
||||||
|
"has_variant_materials": false,
|
||||||
|
"preferred_quality_type": "normal",
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "mp_mini_delta_extruder_0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_start_gcode":
|
||||||
|
{
|
||||||
|
"default_value": ";MPMD Basic Calibration Tutorial: \n; https://www.thingiverse.com/thing:3892011 \n; \n; If you want to put calibration values in your \n; Start Gcode, put them here. \n; \n;If on stock firmware, at minimum, consider adding \n;M665 R here since there is a firmware bug. \n; \n; Calibration part ends here \n; \nG90 ; switch to absolute positioning \nG92 E0 ; reset extrusion distance \nG1 E20 F200 ; purge 20mm of filament to prime nozzle. \nG92 E0 ; reset extrusion distance \nG4 S5 ; Pause for 5 seconds to allow time for removing extruded filament \nG28 ; start from home position \nG1 E-6 F900 ; retract 6mm of filament before starting the bed leveling process \nG92 E0 ; reset extrusion distance \nG4 S5 ; pause for 5 seconds to allow time for removing extruded filament \nG29 P2 Z0.28 ; Auto-level ; ADJUST Z higher or lower to set first layer height. Start with 0.02 adjustments. \nG1 Z30 ; raise Z 30mm to prepare for priming the nozzle \nG1 E5 F200 ; extrude 5mm of filament to help prime the nozzle just prior to the start of the print \nG92 E0 ; reset extrusion distance \nG4 S5 ; pause for 5 seconds to allow time for cleaning the nozzle and build plate if needed "
|
||||||
|
},
|
||||||
|
"machine_end_gcode":
|
||||||
|
{
|
||||||
|
"default_value": "M107; \nM104 S0; turn off hotend heater \nM140 S0; turn off bed heater \nG91; Switch to use Relative Coordinates \nG1 E-2 F300; retract the filament a bit before lifting the nozzle to release some of the pressure \nG1 Z5 E-5 F4800; move nozzle up a bit and retract filament even more \nG28 X0; return to home positions so the nozzle is out of the way \nM84; turn off stepper motors \nG90; switch to absolute positioning \nM82; absolute extrusion mode"
|
||||||
|
},
|
||||||
|
"machine_width": { "default_value": 110 },
|
||||||
|
"machine_depth": { "default_value": 110 },
|
||||||
|
"machine_height": { "default_value": 120 },
|
||||||
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
"machine_shape": { "default_value": "elliptic" },
|
||||||
|
"machine_center_is_zero": { "default_value": true },
|
||||||
|
"machine_nozzle_size": {
|
||||||
|
"default_value": 0.4,
|
||||||
|
"minimum_value": 0.10,
|
||||||
|
"maximum_value": 0.80
|
||||||
|
},
|
||||||
|
"layer_height": {
|
||||||
|
"default_value": 0.14,
|
||||||
|
"minimum_value": 0.04
|
||||||
|
},
|
||||||
|
"layer_height_0": {
|
||||||
|
"default_value": 0.21,
|
||||||
|
"minimum_value": 0.07
|
||||||
|
},
|
||||||
|
"line_width": { "value": "round(machine_nozzle_size * 0.875, 2)" },
|
||||||
|
"material_print_temperature_layer_0": { "value": "material_print_temperature + 5" },
|
||||||
|
"material_bed_temperature_layer_0": { "value": "material_bed_temperature + 5" },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_max_feedrate_x": { "default_value": 150 },
|
||||||
|
"machine_max_feedrate_y": { "default_value": 150 },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 150 },
|
||||||
|
"machine_max_feedrate_e": { "default_value": 50 },
|
||||||
|
"machine_max_acceleration_x": { "default_value": 800 },
|
||||||
|
"machine_max_acceleration_y": { "default_value": 800 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 800 },
|
||||||
|
"machine_max_acceleration_e": { "default_value": 10000 },
|
||||||
|
"machine_acceleration": { "default_value": 3000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 20 },
|
||||||
|
"machine_max_jerk_z": { "default_value": 20 },
|
||||||
|
"machine_max_jerk_e": { "default_value": 5},
|
||||||
|
"retraction_amount": { "default_value": 4 },
|
||||||
|
"retraction_speed": { "default_value": 50 },
|
||||||
|
"retraction_hop_enabled": { "default_value": false },
|
||||||
|
"retract_at_layer_change": { "default_value": true },
|
||||||
|
"coasting_enable": { "default_value": true }
|
||||||
|
}
|
||||||
|
}
|
@ -18,10 +18,10 @@
|
|||||||
"default_value": "skirt"
|
"default_value": "skirt"
|
||||||
},
|
},
|
||||||
"bottom_thickness": {
|
"bottom_thickness": {
|
||||||
"value": "0.5"
|
"value": "0.6"
|
||||||
},
|
},
|
||||||
"brim_width": {
|
"brim_width": {
|
||||||
"value": "2.0"
|
"value": "3.0"
|
||||||
},
|
},
|
||||||
"cool_fan_enabled": {
|
"cool_fan_enabled": {
|
||||||
"value": "True"
|
"value": "True"
|
||||||
@ -39,19 +39,28 @@
|
|||||||
"value": "True"
|
"value": "True"
|
||||||
},
|
},
|
||||||
"cool_min_layer_time": {
|
"cool_min_layer_time": {
|
||||||
"value": "5.0"
|
"value": "1.0"
|
||||||
},
|
},
|
||||||
"cool_min_speed": {
|
"cool_min_speed": {
|
||||||
"value": "10.0"
|
"value": "5.0"
|
||||||
},
|
},
|
||||||
"infill_before_walls": {
|
"infill_before_walls": {
|
||||||
"value": "True"
|
"value": "True"
|
||||||
},
|
},
|
||||||
|
"infill_line_width": {
|
||||||
|
"value": "0.6"
|
||||||
|
},
|
||||||
"infill_overlap": {
|
"infill_overlap": {
|
||||||
"value": "15.0"
|
"value": "15.0"
|
||||||
},
|
},
|
||||||
|
"infill_sparse_density": {
|
||||||
|
"value": "26.0"
|
||||||
|
},
|
||||||
|
"ironing_enabled": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
"layer_0_z_overlap": {
|
"layer_0_z_overlap": {
|
||||||
"value": "0.22"
|
"value": "0.11"
|
||||||
},
|
},
|
||||||
"layer_height_0": {
|
"layer_height_0": {
|
||||||
"value": "0.3"
|
"value": "0.3"
|
||||||
@ -60,11 +69,23 @@
|
|||||||
"value": "100"
|
"value": "100"
|
||||||
},
|
},
|
||||||
"machine_end_gcode": {
|
"machine_end_gcode": {
|
||||||
"default_value": ";End GCode\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 E-5 X-20 Y-20 ;retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nG0 Z{machine_height} ;move the platform all the way down\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nM84 ;steppers off\nG90 ;absolute positioning\nM117 Done"
|
"default_value": ";End GCode\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-4 F300 ;move Z up a bit and retract filament even more\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG0 Z{machine_height} F1800 ;move the platform all the way down\nG28 X0 Y0 F1800 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning\nM117 Done"
|
||||||
},
|
},
|
||||||
"machine_gcode_flavor": {
|
"machine_gcode_flavor": {
|
||||||
"default_value": "RepRap (Marlin/Sprinter)"
|
"default_value": "RepRap (Marlin/Sprinter)"
|
||||||
},
|
},
|
||||||
|
"machine_head_with_fans_polygon":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[-26, -27],
|
||||||
|
[38, -27],
|
||||||
|
[38, 55],
|
||||||
|
[-26, 55]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gantry_height": {
|
||||||
|
"value": "8"
|
||||||
|
},
|
||||||
"machine_height": {
|
"machine_height": {
|
||||||
"value": "100"
|
"value": "100"
|
||||||
},
|
},
|
||||||
@ -72,7 +93,7 @@
|
|||||||
"default_value": "Renkforce RF100"
|
"default_value": "Renkforce RF100"
|
||||||
},
|
},
|
||||||
"machine_start_gcode": {
|
"machine_start_gcode": {
|
||||||
"default_value": ";Start GCode\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E3 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\n;Put printing message on LCD screen\nM117 Printing..."
|
"default_value": ";Sliced at: {day} {date} {time}\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG1 Z5.0 F1800 ;move Z to 5mm\nG28 X0 Y0 F1800 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstop\nG92 E0 ;zero the extruded length\nG1 F200 E6.0 ;extrude 6.0mm of feed stock to build pressure\nG1 Z5.0 F300 ;move the platform down 5mm\nG92 E0 ;zero the extruded length again\nG1 F1800\n;Put printing message on LCD screen\nM117 Printing..."
|
||||||
},
|
},
|
||||||
"machine_width": {
|
"machine_width": {
|
||||||
"value": "100"
|
"value": "100"
|
||||||
@ -90,7 +111,7 @@
|
|||||||
"value": "True"
|
"value": "True"
|
||||||
},
|
},
|
||||||
"raft_airgap": {
|
"raft_airgap": {
|
||||||
"value": "0.22"
|
"value": "0.33"
|
||||||
},
|
},
|
||||||
"raft_base_line_spacing": {
|
"raft_base_line_spacing": {
|
||||||
"value": "3.0"
|
"value": "3.0"
|
||||||
@ -111,22 +132,25 @@
|
|||||||
"value": "0.27"
|
"value": "0.27"
|
||||||
},
|
},
|
||||||
"raft_margin": {
|
"raft_margin": {
|
||||||
"value": "5.0"
|
"value": "6.0"
|
||||||
|
},
|
||||||
|
"raft_speed": {
|
||||||
|
"value": "20.0"
|
||||||
},
|
},
|
||||||
"raft_surface_layers": {
|
"raft_surface_layers": {
|
||||||
"value": "2.0"
|
"value": "2"
|
||||||
},
|
},
|
||||||
"raft_surface_line_spacing": {
|
"raft_surface_line_spacing": {
|
||||||
"value": "3.0"
|
"value": "0.4"
|
||||||
},
|
},
|
||||||
"raft_surface_line_width": {
|
"raft_surface_line_width": {
|
||||||
"value": "0.4"
|
"value": "0.4"
|
||||||
},
|
},
|
||||||
"raft_surface_thickness": {
|
"raft_surface_thickness": {
|
||||||
"value": "0.27"
|
"value": "0.1"
|
||||||
},
|
},
|
||||||
"retraction_amount": {
|
"retraction_amount": {
|
||||||
"value": "2.0"
|
"value": "5.0"
|
||||||
},
|
},
|
||||||
"retraction_combing": {
|
"retraction_combing": {
|
||||||
"default_value": "all"
|
"default_value": "all"
|
||||||
@ -134,15 +158,9 @@
|
|||||||
"retraction_enable": {
|
"retraction_enable": {
|
||||||
"value": "True"
|
"value": "True"
|
||||||
},
|
},
|
||||||
"retraction_hop_enabled": {
|
|
||||||
"value": "1.0"
|
|
||||||
},
|
|
||||||
"retraction_min_travel": {
|
"retraction_min_travel": {
|
||||||
"value": "1.5"
|
"value": "1.5"
|
||||||
},
|
},
|
||||||
"retraction_speed": {
|
|
||||||
"value": "40.0"
|
|
||||||
},
|
|
||||||
"skin_overlap": {
|
"skin_overlap": {
|
||||||
"value": "15.0"
|
"value": "15.0"
|
||||||
},
|
},
|
||||||
@ -185,6 +203,9 @@
|
|||||||
"support_infill_rate": {
|
"support_infill_rate": {
|
||||||
"value": "15 if support_enable else 0 if support_tree_enable else 15"
|
"value": "15 if support_enable else 0 if support_tree_enable else 15"
|
||||||
},
|
},
|
||||||
|
"support_line_width": {
|
||||||
|
"value": "0.6"
|
||||||
|
},
|
||||||
"support_pattern": {
|
"support_pattern": {
|
||||||
"default_value": "lines"
|
"default_value": "lines"
|
||||||
},
|
},
|
||||||
@ -192,13 +213,13 @@
|
|||||||
"default_value": "everywhere"
|
"default_value": "everywhere"
|
||||||
},
|
},
|
||||||
"support_xy_distance": {
|
"support_xy_distance": {
|
||||||
"value": "0.5"
|
"value": "0.7"
|
||||||
},
|
},
|
||||||
"support_z_distance": {
|
"support_z_distance": {
|
||||||
"value": "0.1"
|
"value": "0.35"
|
||||||
},
|
},
|
||||||
"top_thickness": {
|
"top_bottom_thickness": {
|
||||||
"value": "0.5"
|
"value": "0.8"
|
||||||
},
|
},
|
||||||
"wall_thickness": {
|
"wall_thickness": {
|
||||||
"value": "0.8"
|
"value": "0.8"
|
||||||
|
228
resources/definitions/renkforce_rf100_v2.def.json
Normal file
228
resources/definitions/renkforce_rf100_v2.def.json
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Renkforce RF100 V2",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"author": "Simon Peter (based on RF100.ini by Conrad Electronic SE)",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"manufacturer": "Renkforce",
|
||||||
|
"visible": true,
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "renkforce_rf100_extruder_0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"adhesion_type": {
|
||||||
|
"default_value": "skirt"
|
||||||
|
},
|
||||||
|
"bottom_thickness": {
|
||||||
|
"value": "0.6"
|
||||||
|
},
|
||||||
|
"brim_width": {
|
||||||
|
"value": "3.0"
|
||||||
|
},
|
||||||
|
"cool_fan_enabled": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"cool_fan_full_at_height": {
|
||||||
|
"value": "0.5"
|
||||||
|
},
|
||||||
|
"cool_fan_speed_max": {
|
||||||
|
"value": "100.0"
|
||||||
|
},
|
||||||
|
"cool_fan_speed_min": {
|
||||||
|
"value": "100.0"
|
||||||
|
},
|
||||||
|
"cool_lift_head": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"cool_min_layer_time": {
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"cool_min_speed": {
|
||||||
|
"value": "5.0"
|
||||||
|
},
|
||||||
|
"infill_before_walls": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"infill_line_width": {
|
||||||
|
"value": "0.6"
|
||||||
|
},
|
||||||
|
"infill_overlap": {
|
||||||
|
"value": "15.0"
|
||||||
|
},
|
||||||
|
"infill_sparse_density": {
|
||||||
|
"value": "26.0"
|
||||||
|
},
|
||||||
|
"ironing_enabled": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"layer_0_z_overlap": {
|
||||||
|
"value": "0.11"
|
||||||
|
},
|
||||||
|
"layer_height_0": {
|
||||||
|
"value": "0.3"
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"value": "120"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": ";End GCode\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-4 F300 ;move Z up a bit and retract filament even more\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG0 Z{machine_height} F1800 ;move the platform all the way down\nG28 X0 Y0 F1800 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning\nM117 Done"
|
||||||
|
},
|
||||||
|
"machine_gcode_flavor": {
|
||||||
|
"default_value": "RepRap (Marlin/Sprinter)"
|
||||||
|
},
|
||||||
|
"machine_head_with_fans_polygon":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[-26, -27],
|
||||||
|
[38, -27],
|
||||||
|
[38, 55],
|
||||||
|
[-26, 55]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gantry_height": {
|
||||||
|
"value": "8"
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"value": "120"
|
||||||
|
},
|
||||||
|
"machine_name": {
|
||||||
|
"default_value": "Renkforce RF100 V2"
|
||||||
|
},
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": ";Sliced at: {day} {date} {time}\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG1 Z5.0 F1800 ;move Z to 5mm\nG28 X0 Y0 F1800 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstop\nG92 E0 ;zero the extruded length\nG1 F200 E6.0 ;extrude 6.0mm of feed stock to build pressure\nG1 Z5.0 F300 ;move the platform down 5mm\nG92 E0 ;zero the extruded length again\nG1 F1800\n;Put printing message on LCD screen\nM117 Printing..."
|
||||||
|
},
|
||||||
|
"machine_width": {
|
||||||
|
"value": "120"
|
||||||
|
},
|
||||||
|
"material_bed_temperature": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"material_flow": {
|
||||||
|
"value": "110"
|
||||||
|
},
|
||||||
|
"material_print_temperature": {
|
||||||
|
"value": "210.0"
|
||||||
|
},
|
||||||
|
"ooze_shield_enabled": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"raft_airgap": {
|
||||||
|
"value": "0.33"
|
||||||
|
},
|
||||||
|
"raft_base_line_spacing": {
|
||||||
|
"value": "3.0"
|
||||||
|
},
|
||||||
|
"raft_base_line_width": {
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"raft_base_thickness": {
|
||||||
|
"value": "0.3"
|
||||||
|
},
|
||||||
|
"raft_interface_line_spacing": {
|
||||||
|
"value": "3.0"
|
||||||
|
},
|
||||||
|
"raft_interface_line_width": {
|
||||||
|
"value": "0.4"
|
||||||
|
},
|
||||||
|
"raft_interface_thickness": {
|
||||||
|
"value": "0.27"
|
||||||
|
},
|
||||||
|
"raft_margin": {
|
||||||
|
"value": "6.0"
|
||||||
|
},
|
||||||
|
"raft_speed": {
|
||||||
|
"value": "20.0"
|
||||||
|
},
|
||||||
|
"raft_surface_layers": {
|
||||||
|
"value": "2"
|
||||||
|
},
|
||||||
|
"raft_surface_line_spacing": {
|
||||||
|
"value": "0.4"
|
||||||
|
},
|
||||||
|
"raft_surface_line_width": {
|
||||||
|
"value": "0.4"
|
||||||
|
},
|
||||||
|
"raft_surface_thickness": {
|
||||||
|
"value": "0.1"
|
||||||
|
},
|
||||||
|
"retraction_amount": {
|
||||||
|
"value": "5.0"
|
||||||
|
},
|
||||||
|
"retraction_combing": {
|
||||||
|
"default_value": "all"
|
||||||
|
},
|
||||||
|
"retraction_enable": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"retraction_min_travel": {
|
||||||
|
"value": "1.5"
|
||||||
|
},
|
||||||
|
"skin_overlap": {
|
||||||
|
"value": "15.0"
|
||||||
|
},
|
||||||
|
"skirt_brim_minimal_length": {
|
||||||
|
"value": "150.0"
|
||||||
|
},
|
||||||
|
"skirt_gap": {
|
||||||
|
"value": "3.0"
|
||||||
|
},
|
||||||
|
"skirt_line_count": {
|
||||||
|
"value": "3"
|
||||||
|
},
|
||||||
|
"speed_infill": {
|
||||||
|
"value": "50.0"
|
||||||
|
},
|
||||||
|
"speed_layer_0": {
|
||||||
|
"value": "15.0"
|
||||||
|
},
|
||||||
|
"speed_print": {
|
||||||
|
"value": "50.0"
|
||||||
|
},
|
||||||
|
"speed_topbottom": {
|
||||||
|
"value": "30.0"
|
||||||
|
},
|
||||||
|
"speed_travel": {
|
||||||
|
"value": "50.0"
|
||||||
|
},
|
||||||
|
"speed_wall_0": {
|
||||||
|
"value": "25.0"
|
||||||
|
},
|
||||||
|
"speed_wall_x": {
|
||||||
|
"value": "35.0"
|
||||||
|
},
|
||||||
|
"support_angle": {
|
||||||
|
"value": "60.0"
|
||||||
|
},
|
||||||
|
"support_enable": {
|
||||||
|
"value": "False"
|
||||||
|
},
|
||||||
|
"support_infill_rate": {
|
||||||
|
"value": "15 if support_enable else 0 if support_tree_enable else 15"
|
||||||
|
},
|
||||||
|
"support_line_width": {
|
||||||
|
"value": "0.6"
|
||||||
|
},
|
||||||
|
"support_pattern": {
|
||||||
|
"default_value": "lines"
|
||||||
|
},
|
||||||
|
"support_type": {
|
||||||
|
"default_value": "everywhere"
|
||||||
|
},
|
||||||
|
"support_xy_distance": {
|
||||||
|
"value": "0.7"
|
||||||
|
},
|
||||||
|
"support_z_distance": {
|
||||||
|
"value": "0.35"
|
||||||
|
},
|
||||||
|
"top_bottom_thickness": {
|
||||||
|
"value": "0.8"
|
||||||
|
},
|
||||||
|
"wall_thickness": {
|
||||||
|
"value": "0.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
216
resources/definitions/renkforce_rf100_xl.def.json
Normal file
216
resources/definitions/renkforce_rf100_xl.def.json
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Renkforce RF100 XL",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"author": "Simon Peter (based on RF100.ini by Conrad Electronic SE)",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"manufacturer": "Renkforce",
|
||||||
|
"visible": true,
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "renkforce_rf100_xl_extruder_0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"adhesion_type": {
|
||||||
|
"default_value": "skirt"
|
||||||
|
},
|
||||||
|
"bottom_thickness": {
|
||||||
|
"value": "0.6"
|
||||||
|
},
|
||||||
|
"brim_width": {
|
||||||
|
"value": "3.0"
|
||||||
|
},
|
||||||
|
"cool_fan_enabled": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"cool_fan_full_at_height": {
|
||||||
|
"value": "0.5"
|
||||||
|
},
|
||||||
|
"cool_fan_speed_max": {
|
||||||
|
"value": "100.0"
|
||||||
|
},
|
||||||
|
"cool_fan_speed_min": {
|
||||||
|
"value": "100.0"
|
||||||
|
},
|
||||||
|
"cool_lift_head": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"cool_min_layer_time": {
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"cool_min_speed": {
|
||||||
|
"value": "5.0"
|
||||||
|
},
|
||||||
|
"infill_before_walls": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"infill_line_width": {
|
||||||
|
"value": "0.6"
|
||||||
|
},
|
||||||
|
"infill_overlap": {
|
||||||
|
"value": "15.0"
|
||||||
|
},
|
||||||
|
"infill_sparse_density": {
|
||||||
|
"value": "26.0"
|
||||||
|
},
|
||||||
|
"ironing_enabled": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"layer_0_z_overlap": {
|
||||||
|
"value": "0.11"
|
||||||
|
},
|
||||||
|
"layer_height_0": {
|
||||||
|
"value": "0.3"
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"value": "200"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": ";End GCode\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-4 F300 ;move Z up a bit and retract filament even more\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG0 Z{machine_height} F1800 ;move the platform all the way down\nG28 X0 Y0 F1800 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning\nM117 Done"
|
||||||
|
},
|
||||||
|
"machine_gcode_flavor": {
|
||||||
|
"default_value": "RepRap (Marlin/Sprinter)"
|
||||||
|
},
|
||||||
|
"machine_heated_bed": {
|
||||||
|
"default_value": "true"
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"value": "200"
|
||||||
|
},
|
||||||
|
"machine_name": {
|
||||||
|
"default_value": "Renkforce RF100 XL"
|
||||||
|
},
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": ";Sliced at: {day} {date} {time}\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG1 Z5.0 F1800 ;move Z to 5mm\nG28 X0 Y0 F1800 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstop\nG92 E0 ;zero the extruded length\nG1 F200 E6.0 ;extrude 6.0mm of feed stock to build pressure\nG1 Z5.0 F300 ;move the platform down 5mm\nG92 E0 ;zero the extruded length again\nG1 F1800\n;Put printing message on LCD screen\nM117 Printing..."
|
||||||
|
},
|
||||||
|
"machine_width": {
|
||||||
|
"value": "200"
|
||||||
|
},
|
||||||
|
"material_bed_temperature": {
|
||||||
|
"value": "70"
|
||||||
|
},
|
||||||
|
"material_print_temperature": {
|
||||||
|
"value": "210.0"
|
||||||
|
},
|
||||||
|
"ooze_shield_enabled": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"raft_airgap": {
|
||||||
|
"value": "0.33"
|
||||||
|
},
|
||||||
|
"raft_base_line_spacing": {
|
||||||
|
"value": "3.0"
|
||||||
|
},
|
||||||
|
"raft_base_line_width": {
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"raft_base_thickness": {
|
||||||
|
"value": "0.3"
|
||||||
|
},
|
||||||
|
"raft_interface_line_spacing": {
|
||||||
|
"value": "3.0"
|
||||||
|
},
|
||||||
|
"raft_interface_line_width": {
|
||||||
|
"value": "0.4"
|
||||||
|
},
|
||||||
|
"raft_interface_thickness": {
|
||||||
|
"value": "0.27"
|
||||||
|
},
|
||||||
|
"raft_margin": {
|
||||||
|
"value": "6.0"
|
||||||
|
},
|
||||||
|
"raft_speed": {
|
||||||
|
"value": "20.0"
|
||||||
|
},
|
||||||
|
"raft_surface_layers": {
|
||||||
|
"value": "2"
|
||||||
|
},
|
||||||
|
"raft_surface_line_spacing": {
|
||||||
|
"value": "0.4"
|
||||||
|
},
|
||||||
|
"raft_surface_line_width": {
|
||||||
|
"value": "0.4"
|
||||||
|
},
|
||||||
|
"raft_surface_thickness": {
|
||||||
|
"value": "0.1"
|
||||||
|
},
|
||||||
|
"retraction_amount": {
|
||||||
|
"value": "5.0"
|
||||||
|
},
|
||||||
|
"retraction_combing": {
|
||||||
|
"default_value": "all"
|
||||||
|
},
|
||||||
|
"retraction_enable": {
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
"retraction_min_travel": {
|
||||||
|
"value": "1.5"
|
||||||
|
},
|
||||||
|
"skin_overlap": {
|
||||||
|
"value": "15.0"
|
||||||
|
},
|
||||||
|
"skirt_brim_minimal_length": {
|
||||||
|
"value": "150.0"
|
||||||
|
},
|
||||||
|
"skirt_gap": {
|
||||||
|
"value": "3.0"
|
||||||
|
},
|
||||||
|
"skirt_line_count": {
|
||||||
|
"value": "3"
|
||||||
|
},
|
||||||
|
"speed_infill": {
|
||||||
|
"value": "50.0"
|
||||||
|
},
|
||||||
|
"speed_layer_0": {
|
||||||
|
"value": "15.0"
|
||||||
|
},
|
||||||
|
"speed_print": {
|
||||||
|
"value": "50.0"
|
||||||
|
},
|
||||||
|
"speed_topbottom": {
|
||||||
|
"value": "30.0"
|
||||||
|
},
|
||||||
|
"speed_travel": {
|
||||||
|
"value": "50.0"
|
||||||
|
},
|
||||||
|
"speed_wall_0": {
|
||||||
|
"value": "25.0"
|
||||||
|
},
|
||||||
|
"speed_wall_x": {
|
||||||
|
"value": "35.0"
|
||||||
|
},
|
||||||
|
"support_angle": {
|
||||||
|
"value": "60.0"
|
||||||
|
},
|
||||||
|
"support_enable": {
|
||||||
|
"value": "False"
|
||||||
|
},
|
||||||
|
"support_infill_rate": {
|
||||||
|
"value": "15 if support_enable else 0 if support_tree_enable else 15"
|
||||||
|
},
|
||||||
|
"support_line_width": {
|
||||||
|
"value": "0.6"
|
||||||
|
},
|
||||||
|
"support_pattern": {
|
||||||
|
"default_value": "lines"
|
||||||
|
},
|
||||||
|
"support_type": {
|
||||||
|
"default_value": "everywhere"
|
||||||
|
},
|
||||||
|
"support_xy_distance": {
|
||||||
|
"value": "0.7"
|
||||||
|
},
|
||||||
|
"support_z_distance": {
|
||||||
|
"value": "0.35"
|
||||||
|
},
|
||||||
|
"top_bottom_thickness": {
|
||||||
|
"value": "0.8"
|
||||||
|
},
|
||||||
|
"wall_thickness": {
|
||||||
|
"value": "0.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A10M_1.def.json
Normal file
19
resources/extruders/geeetech_A10M_1.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A10M",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 0,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A10M_2.def.json
Normal file
19
resources/extruders/geeetech_A10M_2.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 2",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A10M",
|
||||||
|
"position": "1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 1,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A10T_1.def.json
Normal file
19
resources/extruders/geeetech_A10T_1.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A10T",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 0,
|
||||||
|
"maximum_value": "2"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A10T_2.def.json
Normal file
19
resources/extruders/geeetech_A10T_2.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 2",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A10T",
|
||||||
|
"position": "1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 1,
|
||||||
|
"maximum_value": "2"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A10T_3.def.json
Normal file
19
resources/extruders/geeetech_A10T_3.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 3",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A10T",
|
||||||
|
"position": "2"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 2,
|
||||||
|
"maximum_value": "2"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
17
resources/extruders/geeetech_A10_1.def.json
Normal file
17
resources/extruders/geeetech_A10_1.def.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A10",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": { "default_value": 0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A20M_1.def.json
Normal file
19
resources/extruders/geeetech_A20M_1.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A20M",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 0,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A20M_2.def.json
Normal file
19
resources/extruders/geeetech_A20M_2.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 2",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A20M",
|
||||||
|
"position": "1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 1,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A20T_1.def.json
Normal file
19
resources/extruders/geeetech_A20T_1.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A20T",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 0,
|
||||||
|
"maximum_value": "2"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A20T_2.def.json
Normal file
19
resources/extruders/geeetech_A20T_2.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 2",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A20T",
|
||||||
|
"position": "1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 1,
|
||||||
|
"maximum_value": "2"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
resources/extruders/geeetech_A20T_3.def.json
Normal file
19
resources/extruders/geeetech_A20T_3.def.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 3",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A20T",
|
||||||
|
"position": "2"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 2,
|
||||||
|
"maximum_value": "2"
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
16
resources/extruders/geeetech_A20_1.def.json
Normal file
16
resources/extruders/geeetech_A20_1.def.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_A20",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": { "default_value": 0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
27
resources/extruders/makeit_mx_dual_1st.def.json
Normal file
27
resources/extruders/makeit_mx_dual_1st.def.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "1st Extruder",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "makeit_pro_mx",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 0,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_offset_x": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 },
|
||||||
|
|
||||||
|
"machine_extruder_start_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"machine_extruder_end_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }
|
||||||
|
}
|
||||||
|
}
|
27
resources/extruders/makeit_mx_dual_2nd.def.json
Normal file
27
resources/extruders/makeit_mx_dual_2nd.def.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "2nd Extruder",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "makeit_pro_mx",
|
||||||
|
"position": "1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 1,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_offset_x": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 },
|
||||||
|
|
||||||
|
"machine_extruder_start_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"machine_extruder_end_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }
|
||||||
|
}
|
||||||
|
}
|
15
resources/extruders/mp_mini_delta_extruder_0.def.json
Normal file
15
resources/extruders/mp_mini_delta_extruder_0.def.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 0",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "mp_mini_delta",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": { "default_value": 0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
}
|
||||||
|
}
|
15
resources/extruders/renkforce_rf100_xl_extruder_0.def.json
Normal file
15
resources/extruders/renkforce_rf100_xl_extruder_0.def.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "renkforce_rf100_xl",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": { "default_value": 0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
}
|
||||||
|
}
|
BIN
resources/meshes/mp_mini_delta_platform.stl
Normal file
BIN
resources/meshes/mp_mini_delta_platform.stl
Normal file
Binary file not shown.
@ -238,7 +238,7 @@ UM.MainWindow
|
|||||||
if (filename.toLowerCase().endsWith(".curapackage"))
|
if (filename.toLowerCase().endsWith(".curapackage"))
|
||||||
{
|
{
|
||||||
// Try to install plugin & close.
|
// Try to install plugin & close.
|
||||||
CuraApplication.getPackageManager().installPackageViaDragAndDrop(filename);
|
CuraApplication.installPackageViaDragAndDrop(filename);
|
||||||
packageInstallDialog.text = catalog.i18nc("@label", "This package will be installed after restarting.");
|
packageInstallDialog.text = catalog.i18nc("@label", "This package will be installed after restarting.");
|
||||||
packageInstallDialog.icon = StandardIcon.Information;
|
packageInstallDialog.icon = StandardIcon.Information;
|
||||||
packageInstallDialog.open();
|
packageInstallDialog.open();
|
||||||
|
@ -127,8 +127,8 @@ Item
|
|||||||
icon: StandardIcon.Question
|
icon: StandardIcon.Question
|
||||||
onYes:
|
onYes:
|
||||||
{
|
{
|
||||||
CuraApplication.deleteAll();
|
CuraApplication.resetWorkspace()
|
||||||
Cura.Actions.resetProfile.trigger();
|
Cura.Actions.resetProfile.trigger()
|
||||||
UM.Controller.setActiveStage("PrepareStage")
|
UM.Controller.setActiveStage("PrepareStage")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@ Item
|
|||||||
id: createMenuButton
|
id: createMenuButton
|
||||||
text: catalog.i18nc("@action:button", "Create")
|
text: catalog.i18nc("@action:button", "Create")
|
||||||
iconName: "list-add"
|
iconName: "list-add"
|
||||||
|
enabled: Cura.MachineManager.activeMachine.hasMaterials
|
||||||
onClicked:
|
onClicked:
|
||||||
{
|
{
|
||||||
forceActiveFocus();
|
forceActiveFocus();
|
||||||
@ -174,7 +175,7 @@ Item
|
|||||||
forceActiveFocus();
|
forceActiveFocus();
|
||||||
importMaterialDialog.open();
|
importMaterialDialog.open();
|
||||||
}
|
}
|
||||||
visible: true
|
enabled: Cura.MachineManager.activeMachine.hasMaterials
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export button
|
// Export button
|
||||||
|
@ -202,8 +202,9 @@ Item
|
|||||||
// dragging a tool handle.
|
// dragging a tool handle.
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
x: -base.x + base.mouseX + UM.Theme.getSize("default_margin").width
|
id: toolInfo
|
||||||
y: -base.y + base.mouseY + UM.Theme.getSize("default_margin").height
|
x: visible ? -base.x + base.mouseX + UM.Theme.getSize("default_margin").width: 0
|
||||||
|
y: visible ? -base.y + base.mouseY + UM.Theme.getSize("default_margin").height: 0
|
||||||
|
|
||||||
width: toolHint.width + UM.Theme.getSize("default_margin").width
|
width: toolHint.width + UM.Theme.getSize("default_margin").width
|
||||||
height: toolHint.height;
|
height: toolHint.height;
|
||||||
|
@ -20,7 +20,7 @@ ScrollView
|
|||||||
background: Rectangle // Border
|
background: Rectangle // Border
|
||||||
{
|
{
|
||||||
color: UM.Theme.getColor("main_background")
|
color: UM.Theme.getColor("main_background")
|
||||||
border.color: UM.Theme.getColor("lining")
|
border.color: UM.Theme.getColor("thick_lining")
|
||||||
border.width: UM.Theme.getSize("default_lining").width
|
border.width: UM.Theme.getSize("default_lining").width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,6 +388,7 @@ support_conical_enabled
|
|||||||
support_conical_angle
|
support_conical_angle
|
||||||
support_conical_min_width
|
support_conical_min_width
|
||||||
magic_fuzzy_skin_enabled
|
magic_fuzzy_skin_enabled
|
||||||
|
magic_fuzzy_skin_outside_only
|
||||||
magic_fuzzy_skin_thickness
|
magic_fuzzy_skin_thickness
|
||||||
magic_fuzzy_skin_point_density
|
magic_fuzzy_skin_point_density
|
||||||
magic_fuzzy_skin_point_dist
|
magic_fuzzy_skin_point_dist
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"main_background": [39, 44, 48, 255],
|
"main_background": [39, 44, 48, 255],
|
||||||
"message_background": [39, 44, 48, 255],
|
"message_background": [39, 44, 48, 255],
|
||||||
"wide_lining": [31, 36, 39, 255],
|
"wide_lining": [31, 36, 39, 255],
|
||||||
"thick_lining": [255, 255, 255, 30],
|
"thick_lining": [255, 255, 255, 60],
|
||||||
"lining": [64, 69, 72, 255],
|
"lining": [64, 69, 72, 255],
|
||||||
"viewport_overlay": [30, 36, 39, 255],
|
"viewport_overlay": [30, 36, 39, 255],
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@
|
|||||||
|
|
||||||
"main_background": [255, 255, 255, 255],
|
"main_background": [255, 255, 255, 255],
|
||||||
"wide_lining": [245, 245, 245, 255],
|
"wide_lining": [245, 245, 245, 255],
|
||||||
"thick_lining": [127, 127, 127, 255],
|
"thick_lining": [180, 180, 180, 255],
|
||||||
"lining": [192, 193, 194, 255],
|
"lining": [192, 193, 194, 255],
|
||||||
"viewport_overlay": [246, 246, 246, 255],
|
"viewport_overlay": [246, 246, 246, 255],
|
||||||
|
|
||||||
@ -520,6 +520,7 @@
|
|||||||
"action_button": [15.0, 2.5],
|
"action_button": [15.0, 2.5],
|
||||||
"action_button_icon": [1.0, 1.0],
|
"action_button_icon": [1.0, 1.0],
|
||||||
"action_button_radius": [0.15, 0.15],
|
"action_button_radius": [0.15, 0.15],
|
||||||
|
"dialog_primary_button_padding": [3.0, 0],
|
||||||
|
|
||||||
"radio_button": [1.3, 1.3],
|
"radio_button": [1.3, 1.3],
|
||||||
|
|
||||||
|
65
scripts/check_invalid_imports.py
Normal file
65
scripts/check_invalid_imports.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
"""
|
||||||
|
Run this file with the Cura project root as the working directory
|
||||||
|
Checks for invalid imports. When importing from plugins, there will be no problems when running from source,
|
||||||
|
but for some build types the plugins dir is not on the path, so relative imports should be used instead. eg:
|
||||||
|
from ..UltimakerCloudScope import UltimakerCloudScope <-- OK
|
||||||
|
import plugins.Toolbox.src ... <-- NOT OK
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidImportsChecker:
|
||||||
|
# compile regex
|
||||||
|
REGEX = re.compile(r"^\s*(from plugins|import plugins)")
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
""" Checks for invalid imports
|
||||||
|
|
||||||
|
:return: True if checks passed, False when the test fails
|
||||||
|
"""
|
||||||
|
cwd = os.getcwd()
|
||||||
|
cura_result = checker.check_dir(os.path.join(cwd, "cura"))
|
||||||
|
plugins_result = checker.check_dir(os.path.join(cwd, "plugins"))
|
||||||
|
result = cura_result and plugins_result
|
||||||
|
if not result:
|
||||||
|
print("error: sources contain invalid imports. Use relative imports when referencing plugin source files")
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def check_dir(self, root_dir: str) -> bool:
|
||||||
|
""" Checks a directory for invalid imports
|
||||||
|
|
||||||
|
:return: True if checks passed, False when the test fails
|
||||||
|
"""
|
||||||
|
passed = True
|
||||||
|
for path_like in Path(root_dir).rglob('*.py'):
|
||||||
|
if not self.check_file(str(path_like)):
|
||||||
|
passed = False
|
||||||
|
|
||||||
|
return passed
|
||||||
|
|
||||||
|
def check_file(self, file_path):
|
||||||
|
""" Checks a file for invalid imports
|
||||||
|
|
||||||
|
:return: True if checks passed, False when the test fails
|
||||||
|
"""
|
||||||
|
passed = True
|
||||||
|
with open(file_path, 'r', encoding = "utf-8") as inputFile:
|
||||||
|
# loop through each line in file
|
||||||
|
for line_i, line in enumerate(inputFile, 1):
|
||||||
|
# check if we have a regex match
|
||||||
|
match = self.REGEX.search(line)
|
||||||
|
if match:
|
||||||
|
path = os.path.relpath(file_path)
|
||||||
|
print("{path}:{line_i}:{match}".format(path=path, line_i=line_i, match=match.group(1)))
|
||||||
|
passed = False
|
||||||
|
return passed
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
checker = InvalidImportsChecker()
|
||||||
|
sys.exit(0 if checker.check() else 1)
|
Loading…
x
Reference in New Issue
Block a user