Merge branch 'master' into CURA-7509_plugin_versions_on_crash

This commit is contained in:
Kostas Karmas 2020-06-18 09:13:28 +02:00
commit 039823e68e
57 changed files with 10668 additions and 239 deletions

View File

@ -103,6 +103,11 @@ class Account(QObject):
self._authorization_service.accessTokenChanged.connect(self._onAccessTokenChanged) self._authorization_service.accessTokenChanged.connect(self._onAccessTokenChanged)
self._authorization_service.loadAuthDataFromPreferences() self._authorization_service.loadAuthDataFromPreferences()
@pyqtProperty(int, notify=syncStateChanged)
def syncState(self):
return self._sync_state
def setSyncState(self, service_name: str, state: int) -> None: def setSyncState(self, service_name: str, state: int) -> None:
""" Can be used to register sync services and update account sync states """ Can be used to register sync services and update account sync states

View File

@ -1,22 +1,21 @@
from typing import Optional from typing import Optional
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, pyqtProperty from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
from PyQt5.QtNetwork import QNetworkReply
from UM.TaskManagement.HttpRequestManager import HttpRequestManager from UM.TaskManagement.HttpRequestManager import HttpRequestManager
from cura.UltimakerCloud import UltimakerCloudConstants
class ConnectionStatus(QObject): class ConnectionStatus(QObject):
"""Status info for some web services""" """Provides an estimation of whether internet is reachable
UPDATE_INTERVAL = 10.0 # seconds Estimation is updated with every request through HttpRequestManager.
ULTIMAKER_CLOUD_STATUS_URL = UltimakerCloudConstants.CuraCloudAPIRoot + "/connect/v1/" Acts as a proxy to HttpRequestManager.internetReachableChanged without
exposing the HttpRequestManager in its entirety.
"""
__instance = None # type: Optional[ConnectionStatus] __instance = None # type: Optional[ConnectionStatus]
internetReachableChanged = pyqtSignal() internetReachableChanged = pyqtSignal()
umCloudReachableChanged = pyqtSignal()
@classmethod @classmethod
def getInstance(cls, *args, **kwargs) -> "ConnectionStatus": def getInstance(cls, *args, **kwargs) -> "ConnectionStatus":
@ -24,41 +23,19 @@ class ConnectionStatus(QObject):
cls.__instance = cls(*args, **kwargs) cls.__instance = cls(*args, **kwargs)
return cls.__instance return cls.__instance
def __init__(self, parent: Optional["QObject"] = None): def __init__(self, parent: Optional["QObject"] = None) -> None:
super().__init__(parent) super().__init__(parent)
self._http = HttpRequestManager.getInstance() manager = HttpRequestManager.getInstance()
self._statuses = { self._is_internet_reachable = manager.isInternetReachable # type: bool
self.ULTIMAKER_CLOUD_STATUS_URL: True, manager.internetReachableChanged.connect(self._onInternetReachableChanged)
"http://example.com": True
}
# Create a timer for automatic updates @pyqtProperty(bool, notify = internetReachableChanged)
self._update_timer = QTimer()
self._update_timer.setInterval(int(self.UPDATE_INTERVAL * 1000))
# The timer is restarted automatically
self._update_timer.setSingleShot(False)
self._update_timer.timeout.connect(self._update)
self._update_timer.start()
@pyqtProperty(bool, notify=internetReachableChanged)
def isInternetReachable(self) -> bool: def isInternetReachable(self) -> bool:
# Is any of the test urls reachable? return self._is_internet_reachable
return any(self._statuses.values())
def _update(self): def _onInternetReachableChanged(self, reachable: bool):
for url in self._statuses.keys(): if reachable != self._is_internet_reachable:
self._http.get( self._is_internet_reachable = reachable
url = url,
callback = self._statusCallback,
error_callback = self._statusCallback,
timeout = 5
)
def _statusCallback(self, reply: QNetworkReply, error: QNetworkReply.NetworkError = None):
url = reply.request().url().toString()
prev_statuses = self._statuses.copy()
self._statuses[url] = HttpRequestManager.replyIndicatesSuccess(reply, error)
if any(self._statuses.values()) != any(prev_statuses.values()):
self.internetReachableChanged.emit() self.internetReachableChanged.emit()

View File

@ -207,6 +207,7 @@ class CuraApplication(QtApplication):
self._first_start_machine_actions_model = None self._first_start_machine_actions_model = None
self._welcome_pages_model = WelcomePagesModel(self, parent = self) self._welcome_pages_model = WelcomePagesModel(self, parent = self)
self._add_printer_pages_model = AddPrinterPagesModel(self, parent = self) self._add_printer_pages_model = AddPrinterPagesModel(self, parent = self)
self._add_printer_pages_model_without_cancel = AddPrinterPagesModel(self, parent = self)
self._whats_new_pages_model = WhatsNewPagesModel(self, parent = self) self._whats_new_pages_model = WhatsNewPagesModel(self, parent = self)
self._text_manager = TextManager(parent = self) self._text_manager = TextManager(parent = self)
@ -261,6 +262,10 @@ class CuraApplication(QtApplication):
def ultimakerCloudAccountRootUrl(self) -> str: def ultimakerCloudAccountRootUrl(self) -> str:
return UltimakerCloudConstants.CuraCloudAccountAPIRoot return UltimakerCloudConstants.CuraCloudAccountAPIRoot
@pyqtProperty(str, constant=True)
def ultimakerDigitalFactoryUrl(self) -> str:
return UltimakerCloudConstants.CuraDigitalFactoryURL
def addCommandLineOptions(self): def addCommandLineOptions(self):
"""Adds command line options to the command line parser. """Adds command line options to the command line parser.
@ -647,7 +652,7 @@ class CuraApplication(QtApplication):
return self._global_container_stack return self._global_container_stack
@override(Application) @override(Application)
def setGlobalContainerStack(self, stack: "GlobalStack") -> None: def setGlobalContainerStack(self, stack: Optional["GlobalStack"]) -> None:
self._setLoadingHint(self._i18n_catalog.i18nc("@info:progress", "Initializing Active Machine...")) self._setLoadingHint(self._i18n_catalog.i18nc("@info:progress", "Initializing Active Machine..."))
super().setGlobalContainerStack(stack) super().setGlobalContainerStack(stack)
@ -812,6 +817,7 @@ class CuraApplication(QtApplication):
self._output_device_manager.start() self._output_device_manager.start()
self._welcome_pages_model.initialize() self._welcome_pages_model.initialize()
self._add_printer_pages_model.initialize() self._add_printer_pages_model.initialize()
self._add_printer_pages_model_without_cancel.initialize(cancellable = False)
self._whats_new_pages_model.initialize() self._whats_new_pages_model.initialize()
# Detect in which mode to run and execute that mode # Detect in which mode to run and execute that mode
@ -849,6 +855,7 @@ class CuraApplication(QtApplication):
self.callLater(self._openFile, file_name) self.callLater(self._openFile, file_name)
initializationFinished = pyqtSignal() initializationFinished = pyqtSignal()
showAddPrintersUncancellableDialog = pyqtSignal() # Used to show the add printers dialog with a greyed background
def runWithoutGUI(self): def runWithoutGUI(self):
"""Run Cura without GUI elements and interaction (server mode).""" """Run Cura without GUI elements and interaction (server mode)."""
@ -939,6 +946,10 @@ class CuraApplication(QtApplication):
def getAddPrinterPagesModel(self, *args) -> "AddPrinterPagesModel": def getAddPrinterPagesModel(self, *args) -> "AddPrinterPagesModel":
return self._add_printer_pages_model return self._add_printer_pages_model
@pyqtSlot(result = QObject)
def getAddPrinterPagesModelWithoutCancel(self, *args) -> "AddPrinterPagesModel":
return self._add_printer_pages_model_without_cancel
@pyqtSlot(result = QObject) @pyqtSlot(result = QObject)
def getWhatsNewPagesModel(self, *args) -> "WhatsNewPagesModel": def getWhatsNewPagesModel(self, *args) -> "WhatsNewPagesModel":
return self._whats_new_pages_model return self._whats_new_pages_model

View File

@ -154,7 +154,7 @@ class BaseMaterialsModel(ListModel):
# Update the available materials (ContainerNode) for the current active machine and extruder setup. # Update the available materials (ContainerNode) for the current active machine and extruder setup.
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack() global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
if not global_stack.hasMaterials: if not global_stack or not global_stack.hasMaterials:
return # There are no materials for this machine, so nothing to do. return # There are no materials for this machine, so nothing to do.
extruder_list = global_stack.extruderList extruder_list = global_stack.extruderList
if self._extruder_position > len(extruder_list): if self._extruder_position > len(extruder_list):

View File

@ -7,6 +7,8 @@ from enum import IntEnum
from threading import Thread from threading import Thread
from typing import Union from typing import Union
from UM.Logger import Logger
MYPY = False MYPY = False
if MYPY: if MYPY:
from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice
@ -38,8 +40,10 @@ class FirmwareUpdater(QObject):
return return
self._setFirmwareUpdateState(FirmwareUpdateState.updating) self._setFirmwareUpdateState(FirmwareUpdateState.updating)
try:
self._update_firmware_thread.start() self._update_firmware_thread.start()
except RuntimeError:
Logger.warning("Could not start the update thread, since it's still running!")
def _updateFirmware(self) -> None: def _updateFirmware(self) -> None:
raise NotImplementedError("_updateFirmware needs to be implemented") raise NotImplementedError("_updateFirmware needs to be implemented")

View File

@ -290,9 +290,15 @@ class MachineManager(QObject):
self.activeStackValueChanged.emit() self.activeStackValueChanged.emit()
@pyqtSlot(str) @pyqtSlot(str)
def setActiveMachine(self, stack_id: str) -> None: def setActiveMachine(self, stack_id: Optional[str]) -> None:
self.blurSettings.emit() # Ensure no-one has focus. self.blurSettings.emit() # Ensure no-one has focus.
if not stack_id:
self._application.setGlobalContainerStack(None)
self.globalContainerChanged.emit()
self._application.showAddPrintersUncancellableDialog.emit()
return
container_registry = CuraContainerRegistry.getInstance() container_registry = CuraContainerRegistry.getInstance()
containers = container_registry.findContainerStacks(id = stack_id) containers = container_registry.findContainerStacks(id = stack_id)
if not containers: if not containers:
@ -721,6 +727,8 @@ class MachineManager(QObject):
other_machine_stacks = [s for s in machine_stacks if s["id"] != machine_id] other_machine_stacks = [s for s in machine_stacks if s["id"] != machine_id]
if other_machine_stacks: if other_machine_stacks:
self.setActiveMachine(other_machine_stacks[0]["id"]) self.setActiveMachine(other_machine_stacks[0]["id"])
else:
self.setActiveMachine(None)
metadatas = CuraContainerRegistry.getInstance().findContainerStacksMetadata(id = machine_id) metadatas = CuraContainerRegistry.getInstance().findContainerStacksMetadata(id = machine_id)
if not metadatas: if not metadatas:

View File

@ -10,12 +10,11 @@ from .WelcomePagesModel import WelcomePagesModel
# #
class AddPrinterPagesModel(WelcomePagesModel): class AddPrinterPagesModel(WelcomePagesModel):
def initialize(self) -> None: def initialize(self, cancellable: bool = True) -> None:
self._pages.append({"id": "add_network_or_local_printer", self._pages.append({"id": "add_network_or_local_printer",
"page_url": self._getBuiltinWelcomePagePath("AddNetworkOrLocalPrinterContent.qml"), "page_url": self._getBuiltinWelcomePagePath("AddNetworkOrLocalPrinterContent.qml"),
"next_page_id": "machine_actions", "next_page_id": "machine_actions",
"next_page_button_text": self._catalog.i18nc("@action:button", "Add"), "next_page_button_text": self._catalog.i18nc("@action:button", "Add"),
"previous_page_button_text": self._catalog.i18nc("@action:button", "Cancel"),
}) })
self._pages.append({"id": "add_printer_by_ip", self._pages.append({"id": "add_printer_by_ip",
"page_url": self._getBuiltinWelcomePagePath("AddPrinterByIpContent.qml"), "page_url": self._getBuiltinWelcomePagePath("AddPrinterByIpContent.qml"),
@ -30,6 +29,9 @@ class AddPrinterPagesModel(WelcomePagesModel):
"page_url": self._getBuiltinWelcomePagePath("FirstStartMachineActionsContent.qml"), "page_url": self._getBuiltinWelcomePagePath("FirstStartMachineActionsContent.qml"),
"should_show_function": self.shouldShowMachineActions, "should_show_function": self.shouldShowMachineActions,
}) })
if cancellable:
self._pages[0]["previous_page_button_text"] = self._catalog.i18nc("@action:button", "Cancel")
self.setItems(self._pages) self.setItems(self._pages)

View File

@ -7,6 +7,7 @@
DEFAULT_CLOUD_API_ROOT = "https://api.ultimaker.com" # type: str DEFAULT_CLOUD_API_ROOT = "https://api.ultimaker.com" # type: str
DEFAULT_CLOUD_API_VERSION = "1" # type: str DEFAULT_CLOUD_API_VERSION = "1" # type: str
DEFAULT_CLOUD_ACCOUNT_API_ROOT = "https://account.ultimaker.com" # type: str DEFAULT_CLOUD_ACCOUNT_API_ROOT = "https://account.ultimaker.com" # type: str
DEFAULT_DIGITAL_FACTORY_URL = "https://digitalfactory.ultimaker.com" # type: str
# Container Metadata keys # Container Metadata keys
META_UM_LINKED_TO_ACCOUNT = "um_linked_to_account" META_UM_LINKED_TO_ACCOUNT = "um_linked_to_account"
@ -32,3 +33,10 @@ try:
CuraCloudAccountAPIRoot = DEFAULT_CLOUD_ACCOUNT_API_ROOT CuraCloudAccountAPIRoot = DEFAULT_CLOUD_ACCOUNT_API_ROOT
except ImportError: except ImportError:
CuraCloudAccountAPIRoot = DEFAULT_CLOUD_ACCOUNT_API_ROOT CuraCloudAccountAPIRoot = DEFAULT_CLOUD_ACCOUNT_API_ROOT
try:
from cura.CuraVersion import CuraDigitalFactoryURL # type: ignore
if CuraDigitalFactoryURL == "":
CuraDigitalFactoryURL = DEFAULT_DIGITAL_FACTORY_URL
except ImportError:
CuraDigitalFactoryURL = DEFAULT_DIGITAL_FACTORY_URL

View File

@ -368,15 +368,20 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
machine_name = self._getMachineNameFromSerializedStack(serialized) machine_name = self._getMachineNameFromSerializedStack(serialized)
self._machine_info.metadata_dict = self._getMetaDataDictFromSerializedStack(serialized) self._machine_info.metadata_dict = self._getMetaDataDictFromSerializedStack(serialized)
# Check if the definition has been changed (this usually happens due to an upgrade)
id_list = self._getContainerIdListFromSerialized(serialized)
if id_list[7] != machine_definition_id:
machine_definition_id = id_list[7]
stacks = self._container_registry.findContainerStacks(name = machine_name, type = "machine") stacks = self._container_registry.findContainerStacks(name = machine_name, type = "machine")
self._is_same_machine_type = True self._is_same_machine_type = True
existing_global_stack = None existing_global_stack = None
if stacks: if stacks:
global_stack = stacks[0] global_stack = stacks[0]
existing_global_stack = global_stack existing_global_stack = global_stack
containers_found_dict["machine"] = True containers_found_dict["machine"] = True
# Check if there are any changes at all in any of the container stacks. # Check if there are any changes at all in any of the container stacks.
id_list = self._getContainerIdListFromSerialized(serialized)
for index, container_id in enumerate(id_list): for index, container_id in enumerate(id_list):
# take into account the old empty container IDs # take into account the old empty container IDs
container_id = self._old_empty_profile_id_dict.get(container_id, container_id) container_id = self._old_empty_profile_id_dict.get(container_id, container_id)
@ -661,6 +666,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)] definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)]
for definition_container_file in definition_container_files: for definition_container_file in definition_container_files:
container_id = self._stripFileToId(definition_container_file) container_id = self._stripFileToId(definition_container_file)
definitions = self._container_registry.findDefinitionContainersMetadata(id = container_id) definitions = self._container_registry.findDefinitionContainersMetadata(id = container_id)
if not definitions: if not definitions:
definition_container = DefinitionContainer(container_id) definition_container = DefinitionContainer(container_id)

View File

@ -56,7 +56,7 @@ class PauseAtHeight(Script):
"type": "enum", "type": "enum",
"options": {"marlin": "Marlin (M0)", "griffin": "Griffin (M0, firmware retract)", "bq": "BQ (M25)", "reprap": "RepRap (M226)", "repetier": "Repetier (@pause)"}, "options": {"marlin": "Marlin (M0)", "griffin": "Griffin (M0, firmware retract)", "bq": "BQ (M25)", "reprap": "RepRap (M226)", "repetier": "Repetier (@pause)"},
"default_value": "marlin", "default_value": "marlin",
"value": "\\\"griffin\\\" if machine_gcode_flavor==\\\"Griffin\\\" else \\\"reprap\\\" if machine_gcode_flavor==\\\"RepRap (RepRap)\\\" else \\\"repetier\\\" if machine_gcode_flavor==\\\"Repetier\\\" else \\\"bq\\\" if \\\"BQ\\\" in machine_name else \\\"marlin\\\"" "value": "\\\"griffin\\\" if machine_gcode_flavor==\\\"Griffin\\\" else \\\"reprap\\\" if machine_gcode_flavor==\\\"RepRap (RepRap)\\\" else \\\"repetier\\\" if machine_gcode_flavor==\\\"Repetier\\\" else \\\"bq\\\" if \\\"BQ\\\" in machine_name or \\\"Flying Bear Ghost 4S\\\" in machine_name else \\\"marlin\\\""
}, },
"disarm_timeout": "disarm_timeout":
{ {

View File

@ -4,6 +4,7 @@ import os
from typing import Dict, List, Optional, Set from typing import Dict, List, Optional, Set
from PyQt5.QtNetwork import QNetworkReply from PyQt5.QtNetwork import QNetworkReply
from PyQt5.QtWidgets import QMessageBox
from UM import i18nCatalog from UM import i18nCatalog
from UM.Logger import Logger # To log errors talking to the API. from UM.Logger import Logger # To log errors talking to the API.
@ -50,6 +51,7 @@ class CloudOutputDeviceManager:
self._account = CuraApplication.getInstance().getCuraAPI().account # type: Account self._account = CuraApplication.getInstance().getCuraAPI().account # type: Account
self._api = CloudApiClient(CuraApplication.getInstance(), on_error = lambda error: Logger.log("e", str(error))) self._api = CloudApiClient(CuraApplication.getInstance(), on_error = lambda error: Logger.log("e", str(error)))
self._account.loginStateChanged.connect(self._onLoginStateChanged) self._account.loginStateChanged.connect(self._onLoginStateChanged)
self._removed_printers_message = None # type: Optional[Message]
# Ensure we don't start twice. # Ensure we don't start twice.
self._running = False self._running = False
@ -102,7 +104,7 @@ class CloudOutputDeviceManager:
self._api.getClusters(self._onGetRemoteClustersFinished, self._onGetRemoteClusterFailed) self._api.getClusters(self._onGetRemoteClustersFinished, self._onGetRemoteClusterFailed)
def _onGetRemoteClustersFinished(self, clusters: List[CloudClusterResponse]) -> None: def _onGetRemoteClustersFinished(self, clusters: List[CloudClusterResponse]) -> None:
"""Callback for when the request for getting the clusters is finished.""" """Callback for when the request for getting the clusters is successful and finished."""
self._um_cloud_printers = {m.getMetaDataEntry(self.META_CLUSTER_ID): m for m in self._um_cloud_printers = {m.getMetaDataEntry(self.META_CLUSTER_ID): m for m in
CuraApplication.getInstance().getContainerRegistry().findContainerStacks( CuraApplication.getInstance().getContainerRegistry().findContainerStacks(
@ -120,6 +122,11 @@ class CloudOutputDeviceManager:
self._um_cloud_printers[device_id].setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, True) self._um_cloud_printers[device_id].setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, True)
self._onDevicesDiscovered(new_clusters) self._onDevicesDiscovered(new_clusters)
# Hide the current removed_printers_message, if there is any
if self._removed_printers_message:
self._removed_printers_message.actionTriggered.disconnect(self._onRemovedPrintersMessageActionTriggered)
self._removed_printers_message.hide()
# Remove the CloudOutput device for offline printers # Remove the CloudOutput device for offline printers
offline_device_keys = set(self._remote_clusters.keys()) - set(online_clusters.keys()) offline_device_keys = set(self._remote_clusters.keys()) - set(online_clusters.keys())
for device_id in offline_device_keys: for device_id in offline_device_keys:
@ -269,14 +276,13 @@ class CloudOutputDeviceManager:
return return
# Generate message # Generate message
removed_printers_message = Message( self._removed_printers_message = Message(
title = self.I18N_CATALOG.i18ncp( title = self.I18N_CATALOG.i18ncp(
"info:status", "info:status",
"Cloud connection is not available for a printer", "Cloud connection is not available for a printer",
"Cloud connection is not available for some printers", "Cloud connection is not available for some printers",
len(self.reported_device_ids) len(self.reported_device_ids)
), )
lifetime = 0
) )
device_names = "\n".join(["<li>{} ({})</li>".format(self._um_cloud_printers[device].name, self._um_cloud_printers[device].definition.name) for device in self.reported_device_ids]) device_names = "\n".join(["<li>{} ({})</li>".format(self._um_cloud_printers[device].name, self._um_cloud_printers[device].definition.name) for device in self.reported_device_ids])
message_text = self.I18N_CATALOG.i18ncp( message_text = self.I18N_CATALOG.i18ncp(
@ -291,13 +297,19 @@ class CloudOutputDeviceManager:
"<a href='https://mycloud.ultimaker.com/'>Ultimaker Digital Factory</a>.", "<a href='https://mycloud.ultimaker.com/'>Ultimaker Digital Factory</a>.",
device_names device_names
) )
removed_printers_message.setText(message_text) self._removed_printers_message.setText(message_text)
removed_printers_message.addAction("keep_printer_configurations_action", self._removed_printers_message.addAction("keep_printer_configurations_action",
name = self.I18N_CATALOG.i18nc("@action:button", "Keep printer configurations"), name = self.I18N_CATALOG.i18nc("@action:button", "Keep printer configurations"),
icon = "", icon = "",
description = "Keep the configuration of the cloud printer(s) synced with Cura which are not linked to your account.", description = "Keep the configuration of the cloud printer(s) synced with Cura which are not linked to your account.",
button_align = Message.ActionButtonAlignment.ALIGN_RIGHT) button_align = Message.ActionButtonAlignment.ALIGN_RIGHT)
removed_printers_message.actionTriggered.connect(self._onRemovedPrintersMessageActionTriggered) self._removed_printers_message.addAction("remove_printers_action",
name = self.I18N_CATALOG.i18nc("@action:button", "Remove printers"),
icon = "",
description = "Remove the cloud printer(s) which are not linked to your account.",
button_style = Message.ActionButtonStyle.SECONDARY,
button_align = Message.ActionButtonAlignment.ALIGN_LEFT)
self._removed_printers_message.actionTriggered.connect(self._onRemovedPrintersMessageActionTriggered)
output_device_manager = CuraApplication.getInstance().getOutputDeviceManager() output_device_manager = CuraApplication.getInstance().getOutputDeviceManager()
@ -314,7 +326,7 @@ class CloudOutputDeviceManager:
# Update the printer's metadata to mark it as not linked to the account # Update the printer's metadata to mark it as not linked to the account
device.setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, False) device.setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, False)
removed_printers_message.show() self._removed_printers_message.show()
def _onDiscoveredDeviceRemoved(self, device_id: str) -> None: def _onDiscoveredDeviceRemoved(self, device_id: str) -> None:
device = self._remote_clusters.pop(device_id, None) # type: Optional[CloudOutputDevice] device = self._remote_clusters.pop(device_id, None) # type: Optional[CloudOutputDevice]
@ -402,7 +414,23 @@ class CloudOutputDeviceManager:
if container_cluster_id in self._remote_clusters.keys(): if container_cluster_id in self._remote_clusters.keys():
del self._remote_clusters[container_cluster_id] del self._remote_clusters[container_cluster_id]
@staticmethod def _onRemovedPrintersMessageActionTriggered(self, removed_printers_message: Message, action: str) -> None:
def _onRemovedPrintersMessageActionTriggered(removed_printers_message: Message, action: str) -> None:
if action == "keep_printer_configurations_action": if action == "keep_printer_configurations_action":
removed_printers_message.hide() removed_printers_message.hide()
elif action == "remove_printers_action":
machine_manager = CuraApplication.getInstance().getMachineManager()
remove_printers_ids = {self._um_cloud_printers[i].getId() for i in self.reported_device_ids}
all_ids = {m.getId() for m in CuraApplication.getInstance().getContainerRegistry().findContainerStacks(type = "machine")}
question_title = self.I18N_CATALOG.i18nc("@title:window", "Remove printers?")
question_content = self.I18N_CATALOG.i18nc("@label", "You are about to remove {} printer(s) from Cura. This action cannot be undone. \nAre you sure you want to continue?".format(len(remove_printers_ids)))
if remove_printers_ids == all_ids:
question_content = self.I18N_CATALOG.i18nc("@label", "You are about to remove all printers from Cura. This action cannot be undone. \nAre you sure you want to continue?")
result = QMessageBox.question(None, question_title, question_content)
if result == QMessageBox.No:
return
for machine_cloud_id in self.reported_device_ids:
machine_manager.setActiveMachine(self._um_cloud_printers[machine_cloud_id].getId())
machine_manager.removeMachine(self._um_cloud_printers[machine_cloud_id].getId())
removed_printers_message.hide()

View File

@ -2,10 +2,17 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import configparser import configparser
from typing import Tuple, List from typing import Tuple, List, Dict
import io import io
from UM.VersionUpgrade import VersionUpgrade from UM.VersionUpgrade import VersionUpgrade
# Renamed definition files
_RENAMED_DEFINITION_DICT = {
"dagoma_discoeasy200": "dagoma_discoeasy200_bicolor",
} # type: Dict[str, str]
class VersionUpgrade462to47(VersionUpgrade): class VersionUpgrade462to47(VersionUpgrade):
def upgradePreferences(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: def upgradePreferences(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
""" """
@ -71,6 +78,10 @@ class VersionUpgrade462to47(VersionUpgrade):
ironing_inset = "=(" + ironing_inset + ")" + correction ironing_inset = "=(" + ironing_inset + ")" + correction
parser["values"]["ironing_inset"] = ironing_inset parser["values"]["ironing_inset"] = ironing_inset
# Check renamed definitions
if "definition" in parser["general"] and parser["general"]["definition"] in _RENAMED_DEFINITION_DICT:
parser["general"]["definition"] = _RENAMED_DEFINITION_DICT[parser["general"]["definition"]]
result = io.StringIO() result = io.StringIO()
parser.write(result) parser.write(result)
return [filename], [result.getvalue()] return [filename], [result.getvalue()]
@ -130,7 +141,9 @@ class VersionUpgrade462to47(VersionUpgrade):
script_str = script_str.replace("\\\\", r"\\\\").replace("\n", r"\\\n") # Escape newlines because configparser sees those as section delimiters. script_str = script_str.replace("\\\\", r"\\\\").replace("\n", r"\\\n") # Escape newlines because configparser sees those as section delimiters.
new_scripts_entries.append(script_str) new_scripts_entries.append(script_str)
parser["metadata"]["post_processing_scripts"] = "\n".join(new_scripts_entries) parser["metadata"]["post_processing_scripts"] = "\n".join(new_scripts_entries)
# check renamed definition
if parser.has_option("containers", "7") and parser["containers"]["7"] in _RENAMED_DEFINITION_DICT:
parser["containers"]["7"] = _RENAMED_DEFINITION_DICT[parser["containers"]["7"]]
result = io.StringIO() result = io.StringIO()
parser.write(result) parser.write(result)
return [filename], [result.getvalue()] return [filename], [result.getvalue()]

View File

@ -465,7 +465,7 @@ class XmlMaterialProfile(InstanceContainer):
return "materials" return "materials"
@classmethod @classmethod
def getVersionFromSerialized(cls, serialized: str) -> Optional[int]: def getVersionFromSerialized(cls, serialized: str) -> int:
data = ET.fromstring(serialized) data = ET.fromstring(serialized)
version = XmlMaterialProfile.Version version = XmlMaterialProfile.Version

View File

@ -0,0 +1,70 @@
{
"version": 2,
"name": "Sovol-SV01",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Sovol",
"manufacturer": "Sovol 3D",
"file_formats": "text/x-gcode",
"has_variants": false,
"has_machine_quality": false,
"preferred_quality_type": "draft",
"machine_extruder_trains": {
"0": "SV01_extruder_0"
}
},
"overrides": {
"machine_name": { "default_value": "SV01" },
"machine_extruder_count": { "default_value": 1 },
"machine_width": { "default_value": 280 },
"machine_depth": { "default_value": 260 },
"machine_height": { "default_value": 300 },
"machine_max_feedrate_x": { "value": 500 },
"machine_max_feedrate_y": { "value": 500 },
"machine_max_feedrate_z": { "value": 10 },
"machine_max_feedrate_e": { "value": 50 },
"machine_max_acceleration_x": { "value": 500 },
"machine_max_acceleration_y": { "value": 500 },
"machine_max_acceleration_z": { "value": 100 },
"machine_max_acceleration_e": { "value": 5000 },
"machine_acceleration": { "value": 500 },
"machine_max_jerk_xy": { "value": 10 },
"machine_max_jerk_z": { "value": 0.4 },
"machine_max_jerk_e": { "value": 5 },
"machine_heated_bed": { "default_value": true },
"material_diameter": { "default_value": 1.75 },
"acceleration_print": { "value": 500 },
"acceleration_travel": { "value": 500 },
"acceleration_travel_layer_0": { "value": "acceleration_travel" },
"acceleration_roofing": { "enabled": "acceleration_enabled and roofing_layer_count > 0 and top_layers > 0" },
"jerk_print": { "value": 8 },
"jerk_travel": { "value": "jerk_print" },
"jerk_travel_layer_0": { "value": "jerk_travel" },
"acceleration_enabled": { "value": false },
"jerk_enabled": { "value": false },
"speed_print": { "value": 50.0 } ,
"speed_infill": { "value": "speed_print" },
"skirt_brim_speed": { "value": "speed_layer_0" },
"line_width": { "value": "machine_nozzle_size" },
"optimize_wall_printing_order": { "value": "True" },
"material_initial_print_temperature": { "value": "material_print_temperature" },
"material_final_print_temperature": { "value": "material_print_temperature" },
"material_flow": { "value": 100 },
"z_seam_type": { "value": "'back'" },
"z_seam_corner": { "value": "'z_seam_corner_weighted'" },
"infill_sparse_density": { "value": "20" },
"infill_pattern": { "value": "'lines'" },
"infill_before_walls": { "value": false },
"infill_overlap": { "value": 30.0 },
"skin_overlap": { "value": 10.0 },
"infill_wipe_dist": { "value": 0.0 },
"wall_0_wipe_dist": { "value": 0.0 },
"retraction_amount": { "default_value": 3},
"retraction_speed": { "default_value": 50},
"adhesion_type": { "value": "'skirt'" },
"machine_start_gcode": { "default_value": "M201 X500.00 Y500.00 Z100.00 E5000.00 ;Setup machine max acceleration\nM203 X500.00 Y500.00 Z10.00 E50.00 ;Setup machine max feedrate\nM204 P500.00 R1000.00 T500.00 ;Setup Print/Retract/Travel acceleration\nM205 X8.00 Y8.00 Z0.40 E5.00 ;Setup Jerk\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\n\nG28 ;Home\n\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\n" },
"machine_end_gcode": { "default_value": "G91 ;Relative positioning\nG1 E-2 F2700 ;Retract a bit\nG1 E-2 Z0.2 F2400 ;Retract and raise Z\nG1 X0 Y240 F3000 ;Wipe out\nG1 Z10 ;Raise Z more\nG90 ;Absolute positionning\n\nG1 X0 Y{machine_depth} ;Present print\nM106 S0 ;Turn-off fan\nM104 S0 ;Turn-off hotend\nM140 S0 ;Turn-off bed\n\nM84 X Y E ;Disable all steppers but Z\n" }
}
}

View File

@ -0,0 +1,86 @@
{
"version": 2,
"name": "Sovol-SV02",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Sovol",
"manufacturer": "Sovol 3D",
"file_formats": "text/x-gcode",
"has_variants": false,
"has_machine_quality": false,
"preferred_quality_type": "draft",
"machine_extruder_trains": {
"0": "SV02_extruder_0",
"1": "SV02_extruder_1"
}
},
"overrides": {
"machine_name": { "default_value": "SV02" },
"machine_extruder_count": { "default_value": 2 },
"machine_heated_bed": { "default_value": true },
"machine_width": { "default_value": 300 },
"machine_depth": { "default_value": 250 },
"machine_height": { "default_value": 300 },
"machine_center_is_zero": { "default_value": false },
"retraction_amount": { "default_value": 5},
"retraction_speed": { "default_value": 50},
"gantry_height": { "value": "30" },
"speed_print": { "default_value": 50 },
"material_print_temperature": { "value": 195 },
"material_print_temperature_layer_0": { "value": "material_print_temperature" },
"material_initial_print_temperature": { "value": "material_print_temperature" },
"material_final_print_temperature": { "value": 195 },
"machine_max_feedrate_x": { "value": 500 },
"machine_max_feedrate_y": { "value": 500 },
"machine_max_feedrate_z": { "value": 10 },
"machine_max_feedrate_e": { "value": 50 },
"machine_max_acceleration_x": { "value": 500 },
"machine_max_acceleration_y": { "value": 500 },
"machine_max_acceleration_z": { "value": 100 },
"machine_max_acceleration_e": { "value": 500 },
"machine_acceleration": { "value": 500 },
"machine_max_jerk_xy": { "value": 8 },
"machine_max_jerk_z": { "value": 0.4 },
"machine_max_jerk_e": { "value": 5 },
"machine_heated_bed": { "default_value": true },
"material_diameter": { "default_value": 1.75 },
"infill_overlap": { "default_value": 15 },
"acceleration_print": { "value": 500 },
"acceleration_travel": { "value": 500 },
"acceleration_travel_layer_0": { "value": "acceleration_travel" },
"jerk_print": { "value": 8 },
"jerk_travel": { "value": "jerk_print" },
"jerk_travel_layer_0": { "value": "jerk_travel" },
"acceleration_enabled": { "value": false },
"jerk_enabled": { "value": false },
"machine_max_jerk_xy": { "default_value": 5.0 },
"machine_max_jerk_z": { "default_value": 0.4 },
"machine_max_jerk_e": { "default_value": 5.0 },
"prime_tower_position_x": { "value": "240" },
"prime_tower_position_y": { "value": "190" },
"prime_tower_size": { "value": "30" },
"prime_tower_wipe_enabled": { "default_value": true },
"prime_tower_min_volume": { "value": "((resolveOrValue('prime_tower_size') * 0.5) ** 2 * 3.14159 * resolveOrValue('layer_height'))/2"},
"travel_retract_before_outer_wall": { "default_value": true },
"infill_sparse_density": { "value": "15" },
"infill_pattern": { "value": "'lines'" },
"infill_before_walls": { "value": false },
"infill_overlap": { "value": 30.0 },
"skin_overlap": { "value": 10.0 },
"infill_wipe_dist": { "value": 0.0 },
"wall_0_wipe_dist": { "value": 0.0 },
"adhesion_type": { "value": "'skirt'" },
"brim_replaces_support": { "value": false },
"skirt_gap": { "value": 2 },
"skirt_line_count": { "value": 3 },
"adhesion_extruder_nr": { "value": 1 },
"brim_width": { "value": 4 },
"coasting_enable": { "default_value": true },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": { "default_value": "G21 ;metric values\nG28 ;home all\nG90 ;absolute positioning\nM107 ;start with the fan off\nG1 F2400 Z15.0 ;raise the nozzle 15mm\nM109 S{material_print_temperature} ;Set Extruder Temperature and Wait\nM190 S{material_bed_temperature}; Wait for bed temperature to reach target temp\nT0 ;Switch to Extruder 1\nG1 F3000 X5 Y10 Z0.2 ;move to prime start position\nG92 E0 ;reset extrusion distance\nG1 F600 X160 E5 ;prime nozzle in a line\nG1 F5000 X180 ;quick wipe\nG92 E0 ;reset extrusion distance" },
"machine_end_gcode": { "default_value": "M104 S0 ;hotend off\nM140 S0 ;bed off\nG92 E0\nG1 F2000 E-100 ;retract filament 100mm\nG92 E0\nG1 F3000 X0 Y240 ;move bed for easy part removal\nM84 ;disable steppers" },
"top_bottom_thickness": { "default_value": 1 }
}
}

View File

@ -5702,7 +5702,7 @@
"minimum_value": "0", "minimum_value": "0",
"maximum_value": "min(0.5 * machine_width, 0.5 * machine_depth)", "maximum_value": "min(0.5 * machine_width, 0.5 * machine_depth)",
"minimum_value_warning": "max(extruderValues('prime_tower_line_width')) * 2", "minimum_value_warning": "max(extruderValues('prime_tower_line_width')) * 2",
"maximum_value_warning": "20", "maximum_value_warning": "42",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false "settable_per_extruder": false
}, },
@ -6049,8 +6049,8 @@
}, },
"infill_mesh_order": "infill_mesh_order":
{ {
"label": "Infill Mesh Order", "label": "Mesh Processing Rank",
"description": "Determines which infill mesh is inside the infill of another infill mesh. An infill mesh with a higher order will modify the infill of infill meshes with lower order and normal meshes.", "description": "Determines the priority of this mesh when considering overlapping volumes. Areas where multiple meshes reside will be won by the lower rank mesh. An infill mesh with a higher order will modify the infill of infill meshes with lower order and normal meshes.",
"default_value": 0, "default_value": 0,
"value": "1 if infill_mesh else 0", "value": "1 if infill_mesh else 0",
"minimum_value_warning": "1", "minimum_value_warning": "1",

View File

@ -0,0 +1,31 @@
{
"version": 2,
"name": "TinyBoy E10/J10/L10/M10",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Fred Chan",
"manufacturer": "TinyBoy",
"file_formats": "text/x-gcode",
"has_materials": false,
"has_machine_quality": true,
"preferred_quality_type": "normal",
"machine_extruder_trains":
{
"0": "tinyboy_extruder_0"
}
},
"overrides": {
"machine_name": { "default_value": "TinyBoy E10" },
"machine_width": { "default_value": 100 },
"machine_depth": { "default_value": 100 },
"machine_height": { "default_value": 105 },
"machine_start_gcode": {
"default_value": "G28 ;Home\nG1 Z15.0 F2000 ;Move the platform"
},
"machine_end_gcode": {
"default_value": "M104 S0\nM140 S0\nG92 E80\nG1 E-80 F2000\nG28 X0 Y0\nM84"
}
}
}

View File

@ -0,0 +1,31 @@
{
"version": 2,
"name": "TinyBoy E16/L16/M16",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Fred Chan",
"manufacturer": "TinyBoy",
"file_formats": "text/x-gcode",
"has_materials": false,
"has_machine_quality": true,
"preferred_quality_type": "normal",
"machine_extruder_trains":
{
"0": "tinyboy_extruder_0"
}
},
"overrides": {
"machine_name": { "default_value": "TinyBoy E16" },
"machine_width": { "default_value": 100 },
"machine_depth": { "default_value": 100 },
"machine_height": { "default_value": 165 },
"machine_start_gcode": {
"default_value": "G28 ;Home\nG1 Z15.0 F2000 ;Move the platform"
},
"machine_end_gcode": {
"default_value": "M104 S0\nM140 S0\nG92 E80\nG1 E-80 F2000\nG28 X0 Y0\nM84"
}
}
}

View File

@ -0,0 +1,36 @@
{
"version": 2,
"name": "TinyBoy RA20",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Fred Chan",
"manufacturer": "TinyBoy",
"file_formats": "text/x-gcode",
"platform": "tinyboy_ra20.obj",
"platform_offset": [ 8, -73.3, -8 ],
"has_materials": false,
"has_machine_quality": true,
"preferred_quality_type": "normal",
"machine_extruder_trains":
{
"0": "tinyboy_extruder_0"
}
},
"overrides": {
"machine_name": { "default_value": "TinyBoy RA20" },
"machine_width": { "default_value": 120 },
"machine_depth": { "default_value": 120 },
"machine_height": { "default_value": 205 },
"machine_heated_bed": { "default_value": true },
"machine_start_gcode": {
"default_value": "G28 ;Home\nG1 Z15.0 F2000 ;Move the platform"
},
"machine_end_gcode": {
"default_value": "M104 S0\nM140 S0\nG92 E80\nG1 E-80 F2000\nG28 X0 Y0\nM84"
}
}
}

View File

@ -55,7 +55,7 @@
"default_value": "RepRap (Marlin/Sprinter)" "default_value": "RepRap (Marlin/Sprinter)"
}, },
"machine_start_gcode": { "machine_start_gcode": {
"default_value": "G21 ;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 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." "default_value": "G21 ;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 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 Y50 F9000\n;Put printing message on LCD screen\nM117 Printing..."
}, },
"machine_end_gcode": { "machine_end_gcode": {
"value": "'M104 S0 ;extruder heater off' + ('\\nM140 S0 ;heated bed heater off' if machine_heated_bed else '') + '\\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-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\\nM84 ;steppers off\\nG90 ;absolute positioning'" "value": "'M104 S0 ;extruder heater off' + ('\\nM140 S0 ;heated bed heater off' if machine_heated_bed else '') + '\\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-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\\nM84 ;steppers off\\nG90 ;absolute positioning'"

View File

@ -0,0 +1,15 @@
{
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "SV01",
"position": "0"
},
"overrides": {
"extruder_nr": { "default_value": 0 },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 }
}
}

View File

@ -0,0 +1,26 @@
{
"version": 2,
"name": "Left Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "SV02",
"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 },
"material_diameter": { "default_value": 1.75 },
"machine_nozzle_size": { "default_value": 0.4 },
"machine_extruder_start_code": {
"default_value": "\nT0 ;switch to extruder 1\nG92 E0 ;reset extruder distance\nG1 F2000 E93 ;load filament\nG92 E0 ;reset extruder distance\nM104 S{material_print_temperature}"
},
"machine_extruder_end_code": {
"default_value": "\nG92 E0 ;reset extruder distance\nG1 F800 E-5 ;short retract\nG1 F2400 X250 Y220\nG1 F2000 E-93 ;long retract for filament removal\nG92 E0 ;reset extruder distance\nG90"
}
}
}

View File

@ -0,0 +1,26 @@
{
"version": 2,
"name": "Right Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "SV02",
"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 },
"material_diameter": { "default_value": 1.75 },
"machine_nozzle_size": { "default_value": 0.4 },
"machine_extruder_start_code": {
"default_value": "\nT1 ;switch to extruder 2\nG92 E0 ;reset extruder distance\nG1 F2000 E93 ;load filament\nG92 E0 ;reset extruder distance\nM104 S{material_print_temperature}"
},
"machine_extruder_end_code": {
"default_value": "\nG92 E0 ;reset extruder distance\nG1 F800 E-5 ;short retract\nG1 F2400 X250 Y220\nG1 F2000 E-93 ;long retract for filament removal\nG92 E0 ;reset extruder distance\nG90"
}
}
}

View File

@ -0,0 +1,15 @@
{
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "tinyboy_e10",
"position": "0"
},
"overrides": {
"extruder_nr": { "default_value": 0 },
"machine_nozzle_size": { "default_value": 0.3 },
"material_diameter": { "default_value": 1.75 }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 QtQuick 2.10 import QtQuick 2.10
@ -7,19 +7,16 @@ import QtQuick.Controls 2.3
import UM 1.4 as UM import UM 1.4 as UM
import Cura 1.1 as Cura import Cura 1.1 as Cura
Column Item
{ {
property var profile: null property var profile: Cura.API.account.userProfile
property var loggedIn: false property bool loggedIn: Cura.API.account.isLoggedIn
property var profileImage: "" property var profileImage: Cura.API.account.profileImageUrl
padding: UM.Theme.getSize("wide_margin").height
spacing: UM.Theme.getSize("wide_margin").height
Loader Loader
{ {
id: accountOperations id: accountOperations
anchors.horizontalCenter: parent.horizontalCenter anchors.centerIn: parent
sourceComponent: loggedIn ? userOperations : generalOperations sourceComponent: loggedIn ? userOperations : generalOperations
} }

View File

@ -131,14 +131,9 @@ Item
opacity: opened ? 1 : 0 opacity: opened ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100 } } Behavior on opacity { NumberAnimation { duration: 100 } }
padding: 0
contentItem: AccountDetails contentItem: AccountDetails
{ {}
id: panel
profile: Cura.API.account.userProfile
loggedIn: Cura.API.account.isLoggedIn
profileImage: Cura.API.account.profileImageUrl
}
background: UM.PointingRectangle background: UM.PointingRectangle
{ {

View File

@ -54,6 +54,6 @@ Item
visible: hasAvatar visible: hasAvatar
source: UM.Theme.getIcon("circle_outline") source: UM.Theme.getIcon("circle_outline")
sourceSize: Qt.size(parent.width, parent.height) sourceSize: Qt.size(parent.width, parent.height)
color: UM.Theme.getColor("account_widget_ouline_active") color: UM.Theme.getColor("account_widget_outline_active")
} }
} }

View File

@ -10,7 +10,7 @@ import Cura 1.1 as Cura
Column Column
{ {
spacing: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width
padding: UM.Theme.getSize("default_margin").width
Image Image
{ {
id: machinesImage id: machinesImage

View File

@ -4,15 +4,45 @@ import QtQuick.Controls 2.3
import UM 1.4 as UM import UM 1.4 as UM
import Cura 1.1 as Cura import Cura 1.1 as Cura
Row // sync state icon + message Row // Sync state icon + message
{ {
property var syncState: Cura.API.account.syncState
id: syncRow id: syncRow
width: childrenRect.width width: childrenRect.width
height: childrenRect.height height: childrenRect.height
anchors.horizontalCenter: parent.horizontalCenter
spacing: UM.Theme.getSize("narrow_margin").height spacing: UM.Theme.getSize("narrow_margin").height
states: [
State
{
name: "idle"
when: syncState == Cura.AccountSyncState.IDLE
PropertyChanges { target: icon; source: UM.Theme.getIcon("update")}
},
State
{
name: "syncing"
when: syncState == Cura.AccountSyncState.SYNCING
PropertyChanges { target: icon; source: UM.Theme.getIcon("update") }
PropertyChanges { target: stateLabel; text: catalog.i18nc("@label", "Checking...")}
},
State
{
name: "up_to_date"
when: syncState == Cura.AccountSyncState.SUCCESS
PropertyChanges { target: icon; source: UM.Theme.getIcon("checked") }
PropertyChanges { target: stateLabel; text: catalog.i18nc("@label", "Account synced")}
},
State
{
name: "error"
when: syncState == Cura.AccountSyncState.ERROR
PropertyChanges { target: icon; source: UM.Theme.getIcon("warning_light") }
PropertyChanges { target: stateLabel; text: catalog.i18nc("@label", "Something went wrong...")}
}
]
UM.RecolorImage UM.RecolorImage
{ {
id: icon id: icon
@ -20,7 +50,7 @@ Row // sync state icon + message
height: width height: width
source: Cura.API.account.manualSyncEnabled ? UM.Theme.getIcon("update") : UM.Theme.getIcon("checked") source: Cura.API.account.manualSyncEnabled ? UM.Theme.getIcon("update") : UM.Theme.getIcon("checked")
color: palette.text color: UM.Theme.getColor("account_sync_state_icon")
RotationAnimator RotationAnimator
{ {
@ -30,7 +60,7 @@ Row // sync state icon + message
to: 360 to: 360
duration: 1000 duration: 1000
loops: Animation.Infinite loops: Animation.Infinite
running: true running: syncState == Cura.AccountSyncState.SYNCING
// reset rotation when stopped // reset rotation when stopped
onRunningChanged: { onRunningChanged: {
@ -50,10 +80,13 @@ Row // sync state icon + message
Label Label
{ {
id: stateLabel id: stateLabel
text: catalog.i18nc("@state", catalog.i18nc("@label", "You are in sync with your account")) text: catalog.i18nc("@state", catalog.i18nc("@label", "Account synced"))
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
font: UM.Theme.getFont("medium") font: UM.Theme.getFont("medium")
renderType: Text.NativeRendering renderType: Text.NativeRendering
width: contentWidth + UM.Theme.getSize("default_margin").height
height: contentHeight
verticalAlignment: Text.AlignVCenter
visible: !Cura.API.account.manualSyncEnabled visible: !Cura.API.account.manualSyncEnabled
} }
@ -64,8 +97,10 @@ Row // sync state icon + message
color: UM.Theme.getColor("secondary_button_text") color: UM.Theme.getColor("secondary_button_text")
font: UM.Theme.getFont("medium") font: UM.Theme.getFont("medium")
renderType: Text.NativeRendering renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
height: contentHeight
width: contentWidth + UM.Theme.getSize("default_margin").height
visible: Cura.API.account.manualSyncEnabled visible: Cura.API.account.manualSyncEnabled
height: visible ? accountSyncButton.intrinsicHeight : 0
MouseArea MouseArea
{ {
@ -77,33 +112,4 @@ Row // sync state icon + message
} }
} }
} }
}
signal syncStateChanged(string newState)
onSyncStateChanged: {
if(newState == Cura.AccountSyncState.IDLE){
icon.source = UM.Theme.getIcon("update")
} else if(newState == Cura.AccountSyncState.SYNCING){
icon.source = UM.Theme.getIcon("update")
stateLabel.text = catalog.i18nc("@label", "Checking...")
} else if (newState == Cura.AccountSyncState.SUCCESS) {
icon.source = UM.Theme.getIcon("checked")
stateLabel.text = catalog.i18nc("@label", "You are in sync with your account")
} else if (newState == Cura.AccountSyncState.ERROR) {
icon.source = UM.Theme.getIcon("warning_light")
stateLabel.text = catalog.i18nc("@label", "Something went wrong...")
} else {
print("Error: unexpected sync state: " + newState)
}
if(newState == Cura.AccountSyncState.SYNCING){
updateAnimator.running = true
} else {
updateAnimator.running = false
}
}
Component.onCompleted: Cura.API.account.syncStateChanged.connect(syncStateChanged)
}

View File

@ -9,72 +9,119 @@ import Cura 1.1 as Cura
Column Column
{ {
width: Math.max( spacing: UM.Theme.getSize("narrow_margin").height
Math.max(title.width, accountButton.width) + 2 * UM.Theme.getSize("default_margin").width, topPadding: UM.Theme.getSize("default_margin").height
syncRow.width bottomPadding: UM.Theme.getSize("default_margin").height
) width: childrenRect.width
spacing: UM.Theme.getSize("default_margin").height Item
SystemPalette
{ {
id: palette id: accountInfo
width: childrenRect.width
height: childrenRect.height
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
AvatarImage
{
id: avatar
anchors.verticalCenter: parent.verticalCenter
width: UM.Theme.getSize("main_window_header").height
height: UM.Theme.getSize("main_window_header").height
source: profile["profile_image_url"] ? profile["profile_image_url"] : ""
outlineColor: UM.Theme.getColor("main_background")
}
Rectangle
{
id: initialCircle
width: avatar.width
height: avatar.height
radius: width
anchors.verticalCenter: parent.verticalCenter
color: UM.Theme.getColor("action_button_disabled")
visible: !avatar.hasAvatar
Label
{
id: initialLabel
anchors.centerIn: parent
text: profile["username"].charAt(0).toUpperCase()
font: UM.Theme.getFont("large_bold")
color: UM.Theme.getColor("text")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
}
}
Column
{
anchors.left: avatar.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("narrow_margin").height
width: childrenRect.width
height: childrenRect.height
Label
{
id: username
renderType: Text.NativeRendering
text: profile.username
font: UM.Theme.getFont("large_bold")
color: UM.Theme.getColor("text")
}
SyncState
{
id: syncRow
}
Label
{
id: lastSyncLabel
renderType: Text.NativeRendering
text: catalog.i18nc("@label The argument is a timestamp", "Last update: %1").arg(Cura.API.account.lastSyncDateTime)
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text_medium")
}
}
} }
Label Rectangle
{ {
id: title width: parent.width
anchors.horizontalCenter: parent.horizontalCenter color: UM.Theme.getColor("lining")
horizontalAlignment: Text.AlignHCenter height: UM.Theme.getSize("default_lining").height
renderType: Text.NativeRendering
text: catalog.i18nc("@label The argument is a username.", "Hi %1").arg(profile.username)
font: UM.Theme.getFont("large_bold")
color: UM.Theme.getColor("text")
} }
Cura.TertiaryButton
SyncState {
id: syncRow
}
Label
{ {
id: lastSyncLabel id: cloudButton
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
text: catalog.i18nc("@label The argument is a timestamp", "Last update: %1").arg(Cura.API.account.lastSyncDateTime)
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text_medium")
}
Cura.SecondaryButton
{
id: accountButton
anchors.horizontalCenter: parent.horizontalCenter
width: UM.Theme.getSize("account_button").width width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Ultimaker account") text: catalog.i18nc("@button", "Ultimaker Digital Factory")
onClicked: Qt.openUrlExternally(CuraApplication.ultimakerDigitalFactoryUrl)
fixedWidthMode: false
}
Cura.TertiaryButton
{
id: accountButton
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Ultimaker Account")
onClicked: Qt.openUrlExternally(CuraApplication.ultimakerCloudAccountRootUrl) onClicked: Qt.openUrlExternally(CuraApplication.ultimakerCloudAccountRootUrl)
fixedWidthMode: false fixedWidthMode: false
} }
Label Rectangle
{ {
id: signOutButton width: parent.width
anchors.horizontalCenter: parent.horizontalCenter color: UM.Theme.getColor("lining")
text: catalog.i18nc("@button", "Sign out") height: UM.Theme.getSize("default_lining").height
color: UM.Theme.getColor("secondary_button_text")
font: UM.Theme.getFont("medium")
renderType: Text.NativeRendering
MouseArea
{
anchors.fill: parent
onClicked: Cura.API.account.logout()
hoverEnabled: true
onEntered: signOutButton.font.underline = true
onExited: signOutButton.font.underline = false
}
} }
Cura.TertiaryButton
{
id: signOutButton
onClicked: Cura.API.account.logout()
text: catalog.i18nc("@button", "Sign Out")
}
} }

View File

@ -33,6 +33,8 @@ Button
property alias shadowEnabled: shadow.visible property alias shadowEnabled: shadow.visible
property alias busy: busyIndicator.visible property alias busy: busyIndicator.visible
property bool underlineTextOnHover: false
property alias toolTipContentAlignment: tooltip.contentAlignment property alias toolTipContentAlignment: tooltip.contentAlignment
// This property is used to indicate whether the button has a fixed width or the width would depend on the contents // This property is used to indicate whether the button has a fixed width or the width would depend on the contents
@ -49,6 +51,14 @@ Button
height: UM.Theme.getSize("action_button").height height: UM.Theme.getSize("action_button").height
hoverEnabled: true hoverEnabled: true
onHoveredChanged:
{
if(underlineTextOnHover)
{
buttonText.font.underline = hovered
}
}
contentItem: Row contentItem: Row
{ {
spacing: UM.Theme.getSize("narrow_margin").width spacing: UM.Theme.getSize("narrow_margin").width

View File

@ -84,6 +84,21 @@ UM.MainWindow
CuraApplication.purgeWindows() CuraApplication.purgeWindows()
} }
Connections
{
// This connection is used when there is no ActiveMachine and the user is logged in
target: CuraApplication
onShowAddPrintersUncancellableDialog:
{
Cura.Actions.parent = backgroundItem
// Reuse the welcome dialog item to show "Add a printer" only.
welcomeDialogItem.model = CuraApplication.getAddPrinterPagesModelWithoutCancel()
welcomeDialogItem.progressBarVisible = false
welcomeDialogItem.visible = true
}
}
Connections Connections
{ {
target: CuraApplication target: CuraApplication
@ -117,6 +132,15 @@ UM.MainWindow
welcomeDialogItem.progressBarVisible = false welcomeDialogItem.progressBarVisible = false
welcomeDialogItem.visible = true welcomeDialogItem.visible = true
} }
// Reuse the welcome dialog item to show the "Add printers" dialog. Triggered when there is no active
// machine and the user is logged in.
if (!Cura.MachineManager.activeMachine && Cura.API.account.isLoggedIn)
{
welcomeDialogItem.model = CuraApplication.getAddPrinterPagesModelWithoutCancel()
welcomeDialogItem.progressBarVisible = false
welcomeDialogItem.visible = true
}
} }
} }

View File

@ -14,8 +14,8 @@ UM.Dialog
id: base id: base
title: catalog.i18nc("@title:window", "Discard or Keep changes") title: catalog.i18nc("@title:window", "Discard or Keep changes")
width: UM.Theme.getSize("popup_dialog").width minimumWidth: UM.Theme.getSize("popup_dialog").width
height: UM.Theme.getSize("popup_dialog").height minimumHeight: UM.Theme.getSize("popup_dialog").height
property var changesModel: Cura.UserChangesModel{ id: userChangesModel} property var changesModel: Cura.UserChangesModel{ id: userChangesModel}
onVisibilityChanged: onVisibilityChanged:
{ {
@ -80,6 +80,8 @@ UM.Dialog
property var extruder_name: userChangesModel.getItem(styleData.row).extruder property var extruder_name: userChangesModel.getItem(styleData.row).extruder
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: parent.right
elide: Text.ElideRight
font: UM.Theme.getFont("system") font: UM.Theme.getFont("system")
text: text:
{ {

View File

@ -143,7 +143,7 @@ UM.Dialog
{ {
width: parent.width width: parent.width
height: childrenRect.height height: childrenRect.height
model: Cura.MachineManager.activeMachine.extruderList model: Cura.MachineManager.activeMachine ? Cura.MachineManager.activeMachine.extruderList : null
delegate: Column delegate: Column
{ {
height: childrenRect.height height: childrenRect.height

View File

@ -77,6 +77,8 @@ UM.TooltipArea
anchors.left: fieldLabel.right anchors.left: fieldLabel.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
padding: 0
leftPadding: UM.Theme.getSize("narrow_margin").width
width: numericTextFieldWithUnit.controlWidth width: numericTextFieldWithUnit.controlWidth
height: numericTextFieldWithUnit.controlHeight height: numericTextFieldWithUnit.controlHeight

View File

@ -33,7 +33,7 @@ Cura.ExpandablePopup
} }
contentPadding: UM.Theme.getSize("default_lining").width contentPadding: UM.Theme.getSize("default_lining").width
enabled: Cura.MachineManager.activeMachine.hasMaterials || Cura.MachineManager.activeMachine.hasVariants || Cura.MachineManager.activeMachine.hasVariantBuildplates; //Only let it drop down if there is any configuration that you could change. enabled: Cura.MachineManager.activeMachine ? Cura.MachineManager.activeMachine.hasMaterials || Cura.MachineManager.activeMachine.hasVariants || Cura.MachineManager.activeMachine.hasVariantBuildplates : false; //Only let it drop down if there is any configuration that you could change.
headerItem: Item headerItem: Item
{ {
@ -41,6 +41,7 @@ Cura.ExpandablePopup
RowLayout RowLayout
{ {
anchors.fill: parent anchors.fill: parent
visible: Cura.MachineManager.activeMachine ? Cura.MachineManager.activeMachine.hasMaterials : false
Repeater Repeater
{ {
model: extrudersModel model: extrudersModel
@ -84,7 +85,7 @@ Cura.ExpandablePopup
{ {
id: variantLabel id: variantLabel
visible: Cura.MachineManager.activeMachine.hasVariants visible: Cura.MachineManager.activeMachine ? Cura.MachineManager.activeMachine.hasVariants : false
text: model.variant text: model.variant
elide: Text.ElideRight elide: Text.ElideRight
@ -114,7 +115,7 @@ Cura.ExpandablePopup
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
renderType: Text.NativeRendering renderType: Text.NativeRendering
visible: !Cura.MachineManager.activeMachine.hasMaterials && (Cura.MachineManager.activeMachine.hasVariants || Cura.MachineManager.activeMachine.hasVariantBuildplates) visible: Cura.MachineManager.activeMachine ? !Cura.MachineManager.activeMachine.hasMaterials && (Cura.MachineManager.activeMachine.hasVariants || Cura.MachineManager.activeMachine.hasVariantBuildplates) : false
anchors anchors
{ {

View File

@ -244,7 +244,7 @@ Item
Row Row
{ {
height: visible ? UM.Theme.getSize("print_setup_big_item").height : 0 height: visible ? UM.Theme.getSize("print_setup_big_item").height : 0
visible: Cura.MachineManager.activeMachine.hasMaterials visible: Cura.MachineManager.activeMachine ? Cura.MachineManager.activeMachine.hasMaterials : false
Label Label
{ {
@ -305,7 +305,7 @@ Item
Row Row
{ {
height: visible ? UM.Theme.getSize("print_setup_big_item").height : 0 height: visible ? UM.Theme.getSize("print_setup_big_item").height : 0
visible: Cura.MachineManager.activeMachine.hasVariants visible: Cura.MachineManager.activeMachine ? Cura.MachineManager.activeMachine.hasVariants : false
Label Label
{ {

View File

@ -130,7 +130,11 @@ Item
target: extruderModel target: extruderModel
onModelChanged: onModelChanged:
{ {
supportExtruderCombobox.color = supportExtruderCombobox.model.getItem(supportExtruderCombobox.currentIndex).color var maybeColor = supportExtruderCombobox.model.getItem(supportExtruderCombobox.currentIndex).color
if (maybeColor)
{
supportExtruderCombobox.color = maybeColor
}
} }
} }
onCurrentIndexChanged: onCurrentIndexChanged:

View File

@ -28,11 +28,11 @@ ListView
delegate: MachineSelectorButton delegate: MachineSelectorButton
{ {
text: model.name text: model.name ? model.name : ""
width: listView.width width: listView.width
outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
checked: Cura.MachineManager.activeMachine.id == model.id checked: Cura.MachineManager.activeMachine ? Cura.MachineManager.activeMachine.id == model.id : false
onClicked: onClicked:
{ {

View File

@ -0,0 +1,21 @@
// Copyright (c) 2020 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import UM 1.4 as UM
import Cura 1.1 as Cura
Cura.ActionButton
{
shadowEnabled: true
shadowColor: enabled ? UM.Theme.getColor("secondary_button_shadow"): UM.Theme.getColor("action_button_disabled_shadow")
color: "transparent"
textColor: UM.Theme.getColor("secondary_button_text")
outlineColor: "transparent"
disabledColor: UM.Theme.getColor("action_button_disabled")
textDisabledColor: UM.Theme.getColor("action_button_disabled_text")
hoverColor: "transparent"
underlineTextOnHover: true
}

View File

@ -96,6 +96,8 @@ Item
{ {
UM.Controller.setActiveTool(model.id); UM.Controller.setActiveTool(model.id);
} }
base.state = (index < toolsModel.count/2) ? "anchorAtTop" : "anchorAtBottom";
} }
} }
} }
@ -219,4 +221,40 @@ Item
visible: toolHint.text != "" visible: toolHint.text != ""
} }
states: [
State {
name: "anchorAtTop"
AnchorChanges {
target: panelBorder
anchors.top: base.top
anchors.bottom: undefined
}
PropertyChanges {
target: panelBorder
anchors.topMargin: base.activeY
}
},
State {
name: "anchorAtBottom"
AnchorChanges {
target: panelBorder
anchors.top: undefined
anchors.bottom: base.top
}
PropertyChanges {
target: panelBorder
anchors.bottomMargin: {
if (panelBorder.height > (base.activeY + UM.Theme.getSize("button").height)) {
// panel is tall, align the top of the panel with the top of the first tool button
return -panelBorder.height
}
// align the bottom of the panel with the bottom of the selected tool button
return -(base.activeY + UM.Theme.getSize("button").height)
}
}
}
]
} }

View File

@ -5,7 +5,7 @@ import QtQuick 2.10
import QtQuick.Controls 2.3 import QtQuick.Controls 2.3
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura import Cura 1.1 as Cura
// //
@ -29,8 +29,6 @@ Item
"Custom": -1 "Custom": -1
} }
property int maxItemCountAtOnce: 10 // show at max 10 items at once, otherwise you need to scroll.
// User-editable printer name // User-editable printer name
property alias printerName: printerNameTextField.text property alias printerName: printerNameTextField.text
property alias isPrinterNameValid: printerNameTextField.acceptableInput property alias isPrinterNameValid: printerNameTextField.acceptableInput
@ -54,12 +52,27 @@ Item
} }
} }
function getMachineName()
{
return machineList.model.getItem(machineList.currentIndex) != undefined ? machineList.model.getItem(machineList.currentIndex).name : "";
}
function getMachineMetaDataEntry(key)
{
var metadata = machineList.model.getItem(machineList.currentIndex) != undefined ? machineList.model.getItem(machineList.currentIndex).metadata : undefined;
if (metadata)
{
return metadata[key];
}
return undefined;
}
Component.onCompleted: Component.onCompleted:
{ {
updateCurrentItemUponSectionChange() updateCurrentItemUponSectionChange()
} }
Item Row
{ {
id: localPrinterSelectionItem id: localPrinterSelectionItem
anchors.left: parent.left anchors.left: parent.left
@ -68,19 +81,12 @@ Item
height: childrenRect.height height: childrenRect.height
// ScrollView + ListView for selecting a local printer to add // ScrollView + ListView for selecting a local printer to add
ScrollView Cura.ScrollView
{ {
id: scrollView id: scrollView
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: (maxItemCountAtOnce * UM.Theme.getSize("action_button").height) - UM.Theme.getSize("default_margin").height height: childrenHeight
width: Math.floor(parent.width * 0.4)
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
clip: true
ListView ListView
{ {
@ -183,52 +189,94 @@ Item
} }
} }
} }
}
// Horizontal line // Vertical line
Rectangle Rectangle
{
id: horizontalLine
anchors.top: localPrinterSelectionItem.bottom
anchors.left: parent.left
anchors.right: parent.right
height: UM.Theme.getSize("default_lining").height
color: UM.Theme.getColor("lining")
}
// User-editable printer name row
Row
{
anchors.top: horizontalLine.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: UM.Theme.getSize("default_lining").height
anchors.leftMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").width
Label
{ {
text: catalog.i18nc("@label", "Printer name") id: verticalLine
anchors.verticalCenter: parent.verticalCenter anchors.top: parent.top
font: UM.Theme.getFont("medium") height: childrenHeight - UM.Theme.getSize("default_lining").height
color: UM.Theme.getColor("text") width: UM.Theme.getSize("default_lining").height
verticalAlignment: Text.AlignVCenter color: UM.Theme.getColor("lining")
renderType: Text.NativeRendering
} }
Cura.TextField // User-editable printer name row
Column
{ {
id: printerNameTextField width: Math.floor(parent.width * 0.6)
anchors.verticalCenter: parent.verticalCenter
width: (parent.width / 2) | 0 spacing: UM.Theme.getSize("default_margin").width
placeholderText: catalog.i18nc("@text", "Please give your printer a name") padding: UM.Theme.getSize("default_margin").width
maximumLength: 40
validator: RegExpValidator Label
{ {
regExp: printerNameTextField.machineNameValidator.machineNameRegex width: parent.width
wrapMode: Text.WordWrap
text: base.getMachineName()
color: UM.Theme.getColor("primary_button")
font: UM.Theme.getFont("huge")
elide: Text.ElideRight
}
Grid
{
width: parent.width
columns: 2
rowSpacing: UM.Theme.getSize("default_lining").height
columnSpacing: UM.Theme.getSize("default_margin").width
verticalItemAlignment: Grid.AlignVCenter
Label
{
text: catalog.i18nc("@label", "Manufacturer")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
}
Label
{
text: base.getMachineMetaDataEntry("manufacturer")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
}
Label
{
text: catalog.i18nc("@label", "Profile author")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
}
Label
{
text: base.getMachineMetaDataEntry("author")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
}
Label
{
text: catalog.i18nc("@label", "Printer name")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
}
Cura.TextField
{
id: printerNameTextField
placeholderText: catalog.i18nc("@text", "Please give your printer a name")
maximumLength: 40
validator: RegExpValidator
{
regExp: printerNameTextField.machineNameValidator.machineNameRegex
}
property var machineNameValidator: Cura.MachineNameValidator { }
}
} }
property var machineNameValidator: Cura.MachineNameValidator { }
} }
} }
} }

View File

@ -108,6 +108,12 @@ Item
AddLocalPrinterScrollView AddLocalPrinterScrollView
{ {
id: localPrinterView id: localPrinterView
property int childrenHeight: backButton.y - addLocalPrinterDropDown.y - UM.Theme.getSize("expandable_component_content_header").height - UM.Theme.getSize("default_margin").height
onChildrenHeightChanged:
{
addLocalPrinterDropDown.children[1].height = childrenHeight
}
} }
} }
} }

View File

@ -0,0 +1,46 @@
// Copyright (c) 2020 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import UM 1.1 as UM
ScrollView
{
clip: true
// Setting this property to false hides the scrollbar both when the scrollbar is not needed (child height < height)
// and when the scrollbar is not actively being hovered or pressed
property bool scrollAlwaysVisible: true
ScrollBar.vertical: ScrollBar
{
hoverEnabled: true
policy: parent.scrollAlwaysVisible ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
contentItem: Rectangle
{
implicitWidth: UM.Theme.getSize("scrollbar").width
opacity: (parent.active || parent.parent.scrollAlwaysVisible) ? 1.0 : 0.0
radius: Math.round(width / 2)
color:
{
if (parent.pressed)
{
return UM.Theme.getColor("scrollbar_handle_down")
}
else if (parent.hovered)
{
return UM.Theme.getColor("scrollbar_handle_hover")
}
return UM.Theme.getColor("scrollbar_handle")
}
Behavior on color { ColorAnimation { duration: 100; } }
Behavior on opacity { NumberAnimation { duration: 100 } }
}
}
}

View File

@ -35,6 +35,7 @@ RadioButton 1.0 RadioButton.qml
Scrollable 1.0 Scrollable.qml Scrollable 1.0 Scrollable.qml
TabButton 1.0 TabButton.qml TabButton 1.0 TabButton.qml
TextField 1.0 TextField.qml TextField 1.0 TextField.qml
ScrollView 1.0 ScrollView.qml
# Cura/MachineSettings # Cura/MachineSettings

View File

@ -0,0 +1,61 @@
[general]
version = 4
name = Draft
definition = tinyboy_e10
[metadata]
setting_version = 15
type = quality
quality_type = draft
weight = 0
global_quality = True
[values]
acceleration_enabled = True
acceleration_print = 1800
acceleration_travel = 3000
adhesion_type = skirt
brim_width = 4.0
cool_fan_full_at_height = 0.5
cool_fan_speed = 100
cool_fan_speed_0 = 100
infill_overlap = 15
infill_pattern = zigzag
infill_sparse_density = 25
initial_layer_line_width_factor = 140
jerk_enabled = True
jerk_print = 8
jerk_travel = 10
layer_height = 0.3
layer_height_0 = 0.3
material_bed_temperature = 60
material_diameter = 1.75
material_print_temperature = 200
material_print_temperature_layer_0 = 0
retract_at_layer_change = False
retraction_amount = 6
retraction_hop = 0.075
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 1.5
retraction_speed = 40
skirt_brim_speed = 40
skirt_gap = 5
skirt_line_count = 3
speed_infill = =speed_print
speed_print = 60
speed_support = 60
speed_topbottom = =math.ceil(speed_print * 30 / 60)
speed_travel = 100
speed_wall = =speed_print
speed_wall_x = =speed_print
support_angle = 60
support_enable = True
support_interface_enable = True
support_pattern = triangles
support_roof_enable = True
support_type = everywhere
support_use_towers = False
support_xy_distance = 0.7
top_bottom_thickness = 1.2
wall_thickness = 1.2

View File

@ -0,0 +1,61 @@
[general]
version = 4
name = High
definition = tinyboy_e10
[metadata]
setting_version = 15
type = quality
quality_type = high
weight = 2
global_quality = True
[values]
acceleration_enabled = True
acceleration_print = 1800
acceleration_travel = 3000
adhesion_type = skirt
brim_width = 4.0
cool_fan_full_at_height = 0.5
cool_fan_speed = 100
cool_fan_speed_0 = 100
infill_overlap = 15
infill_pattern = zigzag
infill_sparse_density = 25
initial_layer_line_width_factor = 140
jerk_enabled = True
jerk_print = 8
jerk_travel = 10
layer_height = 0.1
layer_height_0 = 0.1
material_bed_temperature = 60
material_diameter = 1.75
material_print_temperature = 200
material_print_temperature_layer_0 = 0
retract_at_layer_change = False
retraction_amount = 6
retraction_hop = 0.075
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 1.5
retraction_speed = 40
skirt_brim_speed = 40
skirt_gap = 5
skirt_line_count = 3
speed_infill = =speed_print
speed_print = 50
speed_support = 30
speed_topbottom = =math.ceil(speed_print * 20 / 50)
speed_travel = 50
speed_wall = =speed_print
speed_wall_x = =speed_print
support_angle = 60
support_enable = True
support_interface_enable = True
support_pattern = triangles
support_roof_enable = True
support_type = everywhere
support_use_towers = False
support_xy_distance = 0.7
top_bottom_thickness = 1.2
wall_thickness = 1.2

View File

@ -0,0 +1,61 @@
[general]
version = 4
name = Normal
definition = tinyboy_e10
[metadata]
setting_version = 15
type = quality
quality_type = normal
weight = 1
global_quality = True
[values]
acceleration_enabled = True
acceleration_print = 1800
acceleration_travel = 3000
adhesion_type = skirt
brim_width = 4.0
cool_fan_full_at_height = 0.5
cool_fan_speed = 100
cool_fan_speed_0 = 100
infill_overlap = 15
infill_pattern = zigzag
infill_sparse_density = 25
initial_layer_line_width_factor = 140
jerk_enabled = True
jerk_print = 8
jerk_travel = 10
layer_height = 0.2
layer_height_0 = 0.2
material_bed_temperature = 60
material_diameter = 1.75
material_print_temperature = 200
material_print_temperature_layer_0 = 0
retract_at_layer_change = False
retraction_amount = 6
retraction_hop = 0.075
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 1.5
retraction_speed = 40
skirt_brim_speed = 40
skirt_gap = 5
skirt_line_count = 3
speed_infill = =speed_print
speed_print = 50
speed_support = 30
speed_topbottom = =math.ceil(speed_print * 20 / 50)
speed_travel = 100
speed_wall = =speed_print
speed_wall_x = =speed_print
support_angle = 60
support_enable = True
support_interface_enable = True
support_pattern = triangles
support_roof_enable = True
support_type = everywhere
support_use_towers = False
support_xy_distance = 0.7
top_bottom_thickness = 1.2
wall_thickness = 1.2

View File

@ -0,0 +1,61 @@
[general]
version = 4
name = Draft
definition = tinyboy_e16
[metadata]
setting_version = 15
type = quality
quality_type = draft
weight = 0
global_quality = True
[values]
acceleration_enabled = True
acceleration_print = 1800
acceleration_travel = 3000
adhesion_type = skirt
brim_width = 4.0
cool_fan_full_at_height = 0.5
cool_fan_speed = 100
cool_fan_speed_0 = 100
infill_overlap = 15
infill_pattern = zigzag
infill_sparse_density = 25
initial_layer_line_width_factor = 140
jerk_enabled = True
jerk_print = 8
jerk_travel = 10
layer_height = 0.3
layer_height_0 = 0.3
material_bed_temperature = 60
material_diameter = 1.75
material_print_temperature = 200
material_print_temperature_layer_0 = 0
retract_at_layer_change = False
retraction_amount = 6
retraction_hop = 0.075
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 1.5
retraction_speed = 40
skirt_brim_speed = 40
skirt_gap = 5
skirt_line_count = 3
speed_infill = =speed_print
speed_print = 60
speed_support = 60
speed_topbottom = =math.ceil(speed_print * 30 / 60)
speed_travel = 100
speed_wall = =speed_print
speed_wall_x = =speed_print
support_angle = 60
support_enable = True
support_interface_enable = True
support_pattern = triangles
support_roof_enable = True
support_type = everywhere
support_use_towers = False
support_xy_distance = 0.7
top_bottom_thickness = 1.2
wall_thickness = 1.2

View File

@ -0,0 +1,61 @@
[general]
version = 4
name = High
definition = tinyboy_e16
[metadata]
setting_version = 15
type = quality
quality_type = high
weight = 2
global_quality = True
[values]
acceleration_enabled = True
acceleration_print = 1800
acceleration_travel = 3000
adhesion_type = skirt
brim_width = 4.0
cool_fan_full_at_height = 0.5
cool_fan_speed = 100
cool_fan_speed_0 = 100
infill_overlap = 15
infill_pattern = zigzag
infill_sparse_density = 25
initial_layer_line_width_factor = 140
jerk_enabled = True
jerk_print = 8
jerk_travel = 10
layer_height = 0.1
layer_height_0 = 0.1
material_bed_temperature = 60
material_diameter = 1.75
material_print_temperature = 200
material_print_temperature_layer_0 = 0
retract_at_layer_change = False
retraction_amount = 6
retraction_hop = 0.075
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 1.5
retraction_speed = 40
skirt_brim_speed = 40
skirt_gap = 5
skirt_line_count = 3
speed_infill = =speed_print
speed_print = 50
speed_support = 30
speed_topbottom = =math.ceil(speed_print * 20 / 50)
speed_travel = 50
speed_wall = =speed_print
speed_wall_x = =speed_print
support_angle = 60
support_enable = True
support_interface_enable = True
support_pattern = triangles
support_roof_enable = True
support_type = everywhere
support_use_towers = False
support_xy_distance = 0.7
top_bottom_thickness = 1.2
wall_thickness = 1.2

View File

@ -0,0 +1,61 @@
[general]
version = 4
name = Normal
definition = tinyboy_e16
[metadata]
setting_version = 15
type = quality
quality_type = normal
weight = 1
global_quality = True
[values]
acceleration_enabled = True
acceleration_print = 1800
acceleration_travel = 3000
adhesion_type = skirt
brim_width = 4.0
cool_fan_full_at_height = 0.5
cool_fan_speed = 100
cool_fan_speed_0 = 100
infill_overlap = 15
infill_pattern = zigzag
infill_sparse_density = 25
initial_layer_line_width_factor = 140
jerk_enabled = True
jerk_print = 8
jerk_travel = 10
layer_height = 0.2
layer_height_0 = 0.2
material_bed_temperature = 60
material_diameter = 1.75
material_print_temperature = 200
material_print_temperature_layer_0 = 0
retract_at_layer_change = False
retraction_amount = 6
retraction_hop = 0.075
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 1.5
retraction_speed = 40
skirt_brim_speed = 40
skirt_gap = 5
skirt_line_count = 3
speed_infill = =speed_print
speed_print = 50
speed_support = 30
speed_topbottom = =math.ceil(speed_print * 20 / 50)
speed_travel = 100
speed_wall = =speed_print
speed_wall_x = =speed_print
support_angle = 60
support_enable = True
support_interface_enable = True
support_pattern = triangles
support_roof_enable = True
support_type = everywhere
support_use_towers = False
support_xy_distance = 0.7
top_bottom_thickness = 1.2
wall_thickness = 1.2

View File

@ -0,0 +1,61 @@
[general]
version = 4
name = Draft
definition = tinyboy_ra20
[metadata]
setting_version = 15
type = quality
quality_type = draft
weight = 0
global_quality = True
[values]
acceleration_enabled = True
acceleration_print = 1800
acceleration_travel = 3000
adhesion_type = none
brim_width = 4.0
cool_fan_full_at_height = 0.5
cool_fan_speed = 100
cool_fan_speed_0 = 100
infill_overlap = 15
infill_pattern = zigzag
infill_sparse_density = 25
initial_layer_line_width_factor = 140
jerk_enabled = True
jerk_print = 8
jerk_travel = 10
layer_height = 0.3
layer_height_0 = 0.3
material_bed_temperature = 60
material_diameter = 1.75
material_print_temperature = 200
material_print_temperature_layer_0 = 0
retract_at_layer_change = False
retraction_amount = 6
retraction_hop = 0.075
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 1.5
retraction_speed = 40
skirt_brim_speed = 40
skirt_gap = 5
skirt_line_count = 3
speed_infill = =speed_print
speed_print = 60
speed_support = 60
speed_topbottom = =math.ceil(speed_print * 30 / 60)
speed_travel = 100
speed_wall = =speed_print
speed_wall_x = =speed_print
support_angle = 60
support_enable = True
support_interface_enable = True
support_pattern = triangles
support_roof_enable = True
support_type = everywhere
support_use_towers = False
support_xy_distance = 0.7
top_bottom_thickness = 1.2
wall_thickness = 1.2

View File

@ -0,0 +1,61 @@
[general]
version = 4
name = High
definition = tinyboy_ra20
[metadata]
setting_version = 15
type = quality
quality_type = high
weight = 2
global_quality = True
[values]
acceleration_enabled = True
acceleration_print = 1800
acceleration_travel = 3000
adhesion_type = none
brim_width = 4.0
cool_fan_full_at_height = 0.5
cool_fan_speed = 100
cool_fan_speed_0 = 100
infill_overlap = 15
infill_pattern = zigzag
infill_sparse_density = 25
initial_layer_line_width_factor = 140
jerk_enabled = True
jerk_print = 8
jerk_travel = 10
layer_height = 0.1
layer_height_0 = 0.1
material_bed_temperature = 60
material_diameter = 1.75
material_print_temperature = 200
material_print_temperature_layer_0 = 0
retract_at_layer_change = False
retraction_amount = 6
retraction_hop = 0.075
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 1.5
retraction_speed = 40
skirt_brim_speed = 40
skirt_gap = 5
skirt_line_count = 3
speed_infill = =speed_print
speed_print = 50
speed_support = 30
speed_topbottom = =math.ceil(speed_print * 20 / 50)
speed_travel = 50
speed_wall = =speed_print
speed_wall_x = =speed_print
support_angle = 60
support_enable = True
support_interface_enable = True
support_pattern = triangles
support_roof_enable = True
support_type = everywhere
support_use_towers = False
support_xy_distance = 0.7
top_bottom_thickness = 1.2
wall_thickness = 1.2

View File

@ -0,0 +1,61 @@
[general]
version = 4
name = Normal
definition = tinyboy_ra20
[metadata]
setting_version = 15
type = quality
quality_type = normal
weight = 1
global_quality = True
[values]
acceleration_enabled = True
acceleration_print = 1800
acceleration_travel = 3000
adhesion_type = none
brim_width = 4.0
cool_fan_full_at_height = 0.5
cool_fan_speed = 100
cool_fan_speed_0 = 100
infill_overlap = 15
infill_pattern = zigzag
infill_sparse_density = 25
initial_layer_line_width_factor = 140
jerk_enabled = True
jerk_print = 8
jerk_travel = 10
layer_height = 0.2
layer_height_0 = 0.2
material_bed_temperature = 60
material_diameter = 1.75
material_print_temperature = 200
material_print_temperature_layer_0 = 0
retract_at_layer_change = False
retraction_amount = 6
retraction_hop = 0.075
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 1.5
retraction_speed = 40
skirt_brim_speed = 40
skirt_gap = 5
skirt_line_count = 3
speed_infill = =speed_print
speed_print = 50
speed_support = 30
speed_topbottom = =math.ceil(speed_print * 20 / 50)
speed_travel = 100
speed_wall = =speed_print
speed_wall_x = =speed_print
support_angle = 60
support_enable = True
support_interface_enable = True
support_pattern = triangles
support_roof_enable = True
support_type = everywhere
support_use_towers = False
support_xy_distance = 0.7
top_bottom_thickness = 1.2
wall_thickness = 1.2

View File

@ -24,6 +24,8 @@
"main_window_header_button_text_inactive": [128, 128, 128, 255], "main_window_header_button_text_inactive": [128, 128, 128, 255],
"account_sync_state_icon": [255, 255, 255, 204],
"machine_selector_bar": [39, 44, 48, 255], "machine_selector_bar": [39, 44, 48, 255],
"machine_selector_active": [39, 44, 48, 255], "machine_selector_active": [39, 44, 48, 255],
"machine_selector_printer_icon": [204, 204, 204, 255], "machine_selector_printer_icon": [204, 204, 204, 255],

View File

@ -183,6 +183,7 @@
"main_window_header_button_background_hovered": [117, 114, 159, 255], "main_window_header_button_background_hovered": [117, 114, 159, 255],
"account_widget_outline_active": [70, 66, 126, 255], "account_widget_outline_active": [70, 66, 126, 255],
"account_sync_state_icon": [25, 25, 25, 255],
"machine_selector_bar": [31, 36, 39, 255], "machine_selector_bar": [31, 36, 39, 255],
"machine_selector_active": [68, 72, 75, 255], "machine_selector_active": [68, 72, 75, 255],