Merge branch 'ui_rework_4_0' into CURA-5941_restyle_setting_dropdown

This commit is contained in:
Diego Prado Gesto 2018-11-28 11:58:55 +01:00
commit 56f20648f5
95 changed files with 2491 additions and 1765 deletions

View File

@ -20,8 +20,9 @@ Dependencies
------------
* [Uranium](https://github.com/Ultimaker/Uranium) Cura is built on top of the Uranium framework.
* [CuraEngine](https://github.com/Ultimaker/CuraEngine) This will be needed at runtime to perform the actual slicing.
* [fdm_materials](https://github.com/Ultimaker/fdm_materials) Required to load a printer that has swappable material profiles.
* [PySerial](https://github.com/pyserial/pyserial) Only required for USB printing support.
* [python-zeroconf](https://github.com/jstasiak/python-zeroconf) Only required to detect mDNS-enabled printers
* [python-zeroconf](https://github.com/jstasiak/python-zeroconf) Only required to detect mDNS-enabled printers.
Build scripts
-------------

View File

@ -13,6 +13,6 @@ TryExec=@CMAKE_INSTALL_FULL_BINDIR@/cura
Icon=cura-icon
Terminal=false
Type=Application
MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png;model/x3d+xml;
MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png;model/x3d+xml;text/x-gcode;
Categories=Graphics;
Keywords=3D;Printing;Slicer;

View File

@ -19,4 +19,12 @@
<glob-deleteall/>
<glob pattern="*.obj"/>
</mime-type>
<mime-type type="text/x-gcode">
<sub-class-of type="text/plain"/>
<comment>Gcode file</comment>
<icon name="unknown"/>
<glob-deleteall/>
<glob pattern="*.gcode"/>
<glob pattern="*.g"/>
</mime-type>
</mime-info>

View File

@ -46,12 +46,13 @@ class Backup:
# We copy the preferences file to the user data directory in Linux as it's in a different location there.
# When restoring a backup on Linux, we move it back.
if Platform.isLinux():
if Platform.isLinux(): #TODO: This should check for the config directory not being the same as the data directory, rather than hard-coding that to Linux systems.
preferences_file_name = self._application.getApplicationName()
preferences_file = Resources.getPath(Resources.Preferences, "{}.cfg".format(preferences_file_name))
backup_preferences_file = os.path.join(version_data_dir, "{}.cfg".format(preferences_file_name))
Logger.log("d", "Copying preferences file from %s to %s", preferences_file, backup_preferences_file)
shutil.copyfile(preferences_file, backup_preferences_file)
if os.path.exists(preferences_file) and (not os.path.exists(backup_preferences_file) or not os.path.samefile(preferences_file, backup_preferences_file)):
Logger.log("d", "Copying preferences file from %s to %s", preferences_file, backup_preferences_file)
shutil.copyfile(preferences_file, backup_preferences_file)
# Create an empty buffer and write the archive to it.
buffer = io.BytesIO()

View File

@ -3,7 +3,7 @@
from PyQt5.QtCore import QObject, QUrl
from PyQt5.QtGui import QDesktopServices
from typing import List, TYPE_CHECKING
from typing import List, TYPE_CHECKING, cast
from UM.Event import CallFunctionEvent
from UM.FlameProfiler import pyqtSlot
@ -61,8 +61,10 @@ class CuraActions(QObject):
operation = GroupedOperation()
for node in Selection.getAllSelectedObjects():
current_node = node
while current_node.getParent() and current_node.getParent().callDecoration("isGroup"):
current_node = current_node.getParent()
parent_node = current_node.getParent()
while parent_node and parent_node.callDecoration("isGroup"):
current_node = parent_node
parent_node = current_node.getParent()
# This was formerly done with SetTransformOperation but because of
# unpredictable matrix deconstruction it was possible that mirrors
@ -150,13 +152,13 @@ class CuraActions(QObject):
root = cura.CuraApplication.CuraApplication.getInstance().getController().getScene().getRoot()
nodes_to_change = []
nodes_to_change = [] # type: List[SceneNode]
for node in Selection.getAllSelectedObjects():
parent_node = node # Find the parent node to change instead
while parent_node.getParent() != root:
parent_node = parent_node.getParent()
parent_node = cast(SceneNode, parent_node.getParent())
for single_node in BreadthFirstIterator(parent_node): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
for single_node in BreadthFirstIterator(parent_node): # type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
nodes_to_change.append(single_node)
if not nodes_to_change:

View File

@ -1663,7 +1663,9 @@ class CuraApplication(QtApplication):
is_non_sliceable = "." + file_extension in self._non_sliceable_extensions
if is_non_sliceable:
self.callLater(lambda: self.getController().setActiveView("SimulationView"))
# Need to switch first to the preview stage and then to layer view
self.callLater(lambda: (self.getController().setActiveStage("PreviewStage"),
self.getController().setActiveView("SimulationView")))
block_slicing_decorator = BlockSlicingDecorator()
node.addDecorator(block_slicing_decorator)

View File

@ -14,8 +14,7 @@ from UM.Logger import Logger
from UM.Qt.Duration import Duration
from UM.Scene.SceneNode import SceneNode
from UM.i18n import i18nCatalog
from UM.MimeTypeDatabase import MimeTypeDatabase
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError
from typing import TYPE_CHECKING
@ -361,7 +360,7 @@ class PrintInformation(QObject):
try:
mime_type = MimeTypeDatabase.getMimeTypeForFile(name)
data = mime_type.stripExtension(name)
except:
except MimeTypeNotFoundError:
Logger.log("w", "Unsupported Mime Type Database file extension %s", name)
if data is not None and check_name is not None:
@ -395,28 +394,14 @@ class PrintInformation(QObject):
return
active_machine_type_name = global_container_stack.definition.getName()
abbr_machine = ""
for word in re.findall(r"[\w']+", active_machine_type_name):
if word.lower() == "ultimaker":
abbr_machine += "UM"
elif word.isdigit():
abbr_machine += word
else:
stripped_word = self._stripAccents(word.upper())
# - use only the first character if the word is too long (> 3 characters)
# - use the whole word if it's not too long (<= 3 characters)
if len(stripped_word) > 3:
stripped_word = stripped_word[0]
abbr_machine += stripped_word
self._abbr_machine = abbr_machine
self._abbr_machine = self._application.getMachineManager().getAbbreviatedMachineName(active_machine_type_name)
## Utility method that strips accents from characters (eg: â -> a)
def _stripAccents(self, to_strip: str) -> str:
return ''.join(char for char in unicodedata.normalize('NFD', to_strip) if unicodedata.category(char) != 'Mn')
@pyqtSlot(result = "QVariantMap")
def getFeaturePrintTimes(self):
def getFeaturePrintTimes(self) -> Dict[str, Duration]:
result = {}
if self._active_build_plate not in self._print_times_per_feature:
self._initPrintTimesPerFeature(self._active_build_plate)

View File

@ -147,6 +147,9 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
request.setHeader(QNetworkRequest.UserAgentHeader, self._user_agent)
return request
def createFormPart(self, content_header: str, data: bytes, content_type: Optional[str] = None) -> QHttpPart:
return self._createFormPart(content_header, data, content_type)
def _createFormPart(self, content_header: str, data: bytes, content_type: Optional[str] = None) -> QHttpPart:
part = QHttpPart()

View File

@ -211,6 +211,11 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._unique_configurations.sort(key = lambda k: k.printerType)
self.uniqueConfigurationsChanged.emit()
# Returns the unique configurations of the printers within this output device
@pyqtProperty("QStringList", notify = uniqueConfigurationsChanged)
def uniquePrinterTypes(self) -> List[str]:
return list(set([configuration.printerType for configuration in self._unique_configurations]))
def _onPrintersChanged(self) -> None:
for printer in self._printers:
printer.configurationChanged.connect(self._updateUniqueConfigurations)
@ -238,4 +243,4 @@ class PrinterOutputDevice(QObject, OutputDevice):
if not self._firmware_updater:
return
self._firmware_updater.updateFirmware(firmware_file)
self._firmware_updater.updateFirmware(firmware_file)

View File

@ -3,6 +3,8 @@
import collections
import time
import re
import unicodedata
from typing import Any, Callable, List, Dict, TYPE_CHECKING, Optional, cast
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
@ -64,7 +66,7 @@ class MachineManager(QObject):
self.machine_extruder_material_update_dict = collections.defaultdict(list) #type: Dict[str, List[Callable[[], None]]]
self._instance_container_timer = QTimer() #type: QTimer
self._instance_container_timer = QTimer() # type: QTimer
self._instance_container_timer.setInterval(250)
self._instance_container_timer.setSingleShot(True)
self._instance_container_timer.timeout.connect(self.__emitChangedSignals)
@ -74,7 +76,7 @@ class MachineManager(QObject):
self._application.globalContainerStackChanged.connect(self._onGlobalContainerChanged)
self._container_registry.containerLoadComplete.connect(self._onContainersChanged)
## When the global container is changed, active material probably needs to be updated.
# When the global container is changed, active material probably needs to be updated.
self.globalContainerChanged.connect(self.activeMaterialChanged)
self.globalContainerChanged.connect(self.activeVariantChanged)
self.globalContainerChanged.connect(self.activeQualityChanged)
@ -115,15 +117,15 @@ class MachineManager(QObject):
self._material_incompatible_message = Message(catalog.i18nc("@info:status",
"The selected material is incompatible with the selected machine or configuration."),
title = catalog.i18nc("@info:title", "Incompatible Material")) #type: Message
title = catalog.i18nc("@info:title", "Incompatible Material")) # type: Message
containers = CuraContainerRegistry.getInstance().findInstanceContainers(id = self.activeMaterialId) #type: List[InstanceContainer]
containers = CuraContainerRegistry.getInstance().findInstanceContainers(id = self.activeMaterialId) # type: List[InstanceContainer]
if containers:
containers[0].nameChanged.connect(self._onMaterialNameChanged)
self._material_manager = self._application.getMaterialManager() #type: MaterialManager
self._variant_manager = self._application.getVariantManager() #type: VariantManager
self._quality_manager = self._application.getQualityManager() #type: QualityManager
self._material_manager = self._application.getMaterialManager() # type: MaterialManager
self._variant_manager = self._application.getVariantManager() # type: VariantManager
self._quality_manager = self._application.getQualityManager() # type: QualityManager
# When the materials lookup table gets updated, it can mean that a material has its name changed, which should
# be reflected on the GUI. This signal emission makes sure that it happens.
@ -156,7 +158,7 @@ class MachineManager(QObject):
blurSettings = pyqtSignal() # Emitted to force fields in the advanced sidebar to un-focus, so they update properly
outputDevicesChanged = pyqtSignal()
currentConfigurationChanged = pyqtSignal() # Emitted every time the current configurations of the machine changes
currentConfigurationChanged = pyqtSignal() # Emitted every time the current configurations of the machine changes
printerConnectedStatusChanged = pyqtSignal() # Emitted every time the active machine change or the outputdevices change
rootMaterialChanged = pyqtSignal()
@ -201,7 +203,7 @@ class MachineManager(QObject):
extruder_configuration.hotendID = extruder.variant.getName() if extruder.variant != empty_variant_container else None
self._current_printer_configuration.extruderConfigurations.append(extruder_configuration)
# an empty build plate configuration from the network printer is presented as an empty string, so use "" for an
# An empty build plate configuration from the network printer is presented as an empty string, so use "" for an
# empty build plate.
self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.getProperty("machine_buildplate_type", "value") if self._global_container_stack.variant != empty_variant_container else ""
self.currentConfigurationChanged.emit()
@ -247,7 +249,7 @@ class MachineManager(QObject):
self.updateNumberExtrudersEnabled()
self.globalContainerChanged.emit()
# after switching the global stack we reconnect all the signals and set the variant and material references
# After switching the global stack we reconnect all the signals and set the variant and material references
if self._global_container_stack:
self._application.getPreferences().setValue("cura/active_machine", self._global_container_stack.getId())
@ -261,7 +263,7 @@ class MachineManager(QObject):
if global_variant.getMetaDataEntry("hardware_type") != "buildplate":
self._global_container_stack.setVariant(empty_variant_container)
# set the global material to empty as we now use the extruder stack at all times - CURA-4482
# Set the global material to empty as we now use the extruder stack at all times - CURA-4482
global_material = self._global_container_stack.material
if global_material != empty_material_container:
self._global_container_stack.setMaterial(empty_material_container)
@ -419,7 +421,7 @@ class MachineManager(QObject):
# Not a very pretty solution, but the extruder manager doesn't really know how many extruders there are
machine_extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value")
extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
count = 1 # we start with the global stack
count = 1 # We start with the global stack
for stack in extruder_stacks:
md = stack.getMetaData()
if "position" in md and int(md["position"]) >= machine_extruder_count:
@ -646,7 +648,7 @@ class MachineManager(QObject):
new_value = self._active_container_stack.getProperty(key, "value")
extruder_stacks = [stack for stack in ExtruderManager.getInstance().getActiveExtruderStacks()]
# check in which stack the value has to be replaced
# Check in which stack the value has to be replaced
for extruder_stack in extruder_stacks:
if extruder_stack != self._active_container_stack and extruder_stack.getProperty(key, "value") != new_value:
extruder_stack.userChanges.setProperty(key, "value", new_value) # TODO: nested property access, should be improved
@ -662,7 +664,7 @@ class MachineManager(QObject):
for key in self._active_container_stack.userChanges.getAllKeys():
new_value = self._active_container_stack.getProperty(key, "value")
# check if the value has to be replaced
# Check if the value has to be replaced
extruder_stack.userChanges.setProperty(key, "value", new_value)
@pyqtProperty(str, notify = activeVariantChanged)
@ -731,7 +733,7 @@ class MachineManager(QObject):
# If the machine that is being removed is the currently active machine, set another machine as the active machine.
activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id)
# activate a new machine before removing a machine because this is safer
# Activate a new machine before removing a machine because this is safer
if activate_new_machine:
machine_stacks = CuraContainerRegistry.getInstance().findContainerStacksMetadata(type = "machine")
other_machine_stacks = [s for s in machine_stacks if s["id"] != machine_id]
@ -909,21 +911,18 @@ class MachineManager(QObject):
# After CURA-4482 this should not be the case anymore, but we still want to support older project files.
global_user_container = self._global_container_stack.userChanges
# Make sure extruder_stacks exists
extruder_stacks = [] #type: List[ExtruderStack]
if previous_extruder_count == 1:
extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
global_user_container = self._global_container_stack.userChanges
for setting_instance in global_user_container.findInstances():
setting_key = setting_instance.definition.key
settable_per_extruder = self._global_container_stack.getProperty(setting_key, "settable_per_extruder")
if settable_per_extruder:
limit_to_extruder = int(self._global_container_stack.getProperty(setting_key, "limit_to_extruder"))
extruder_stack = extruder_stacks[max(0, limit_to_extruder)]
extruder_stack.userChanges.setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value"))
extruder_position = max(0, limit_to_extruder)
extruder_stack = self.getExtruder(extruder_position)
if extruder_stack:
extruder_stack.userChanges.setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value"))
else:
Logger.log("e", "Unable to find extruder on position %s", extruder_position)
global_user_container.removeInstance(setting_key)
# Signal that the global stack has changed
@ -932,10 +931,9 @@ class MachineManager(QObject):
@pyqtSlot(int, result = QObject)
def getExtruder(self, position: int) -> Optional[ExtruderStack]:
extruder = None
if self._global_container_stack:
extruder = self._global_container_stack.extruders.get(str(position))
return extruder
return self._global_container_stack.extruders.get(str(position))
return None
def updateDefaultExtruder(self) -> None:
if self._global_container_stack is None:
@ -1001,12 +999,12 @@ class MachineManager(QObject):
if not enabled and position == ExtruderManager.getInstance().activeExtruderIndex:
ExtruderManager.getInstance().setActiveExtruderIndex(int(self._default_extruder_position))
# ensure that the quality profile is compatible with current combination, or choose a compatible one if available
# Ensure that the quality profile is compatible with current combination, or choose a compatible one if available
self._updateQualityWithMaterial()
self.extruderChanged.emit()
# update material compatibility color
# Update material compatibility color
self.activeQualityGroupChanged.emit()
# update items in SettingExtruder
# Update items in SettingExtruder
ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId())
# Make sure the front end reflects changes
self.forceUpdateAllSettings()
@ -1080,7 +1078,6 @@ class MachineManager(QObject):
return result
#
# Sets all quality and quality_changes containers to empty_quality and empty_quality_changes containers
# for all stacks in the currently active machine.
#
@ -1139,7 +1136,7 @@ class MachineManager(QObject):
def _setQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup") -> None:
if self._global_container_stack is None:
return #Can't change that.
return # Can't change that.
quality_type = quality_changes_group.quality_type
# A custom quality can be created based on "not supported".
# In that case, do not set quality containers to empty.
@ -1209,7 +1206,7 @@ class MachineManager(QObject):
self.rootMaterialChanged.emit()
def activeMaterialsCompatible(self) -> bool:
# check material - variant compatibility
# Check material - variant compatibility
if self._global_container_stack is not None:
if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)):
for position, extruder in self._global_container_stack.extruders.items():
@ -1419,7 +1416,7 @@ class MachineManager(QObject):
material_diameter, root_material_id)
self.setMaterial(position, material_node)
## global_stack: if you want to provide your own global_stack instead of the current active one
## Global_stack: if you want to provide your own global_stack instead of the current active one
# if you update an active machine, special measures have to be taken.
@pyqtSlot(str, "QVariant")
def setMaterial(self, position: str, container_node, global_stack: Optional["GlobalStack"] = None) -> None:
@ -1537,3 +1534,22 @@ class MachineManager(QObject):
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
self.updateMaterialWithVariant(None)
self._updateQualityWithMaterial()
## This function will translate any printer type name to an abbreviated printer type name
@pyqtSlot(str, result = str)
def getAbbreviatedMachineName(self, machine_type_name: str) -> str:
abbr_machine = ""
for word in re.findall(r"[\w']+", machine_type_name):
if word.lower() == "ultimaker":
abbr_machine += "UM"
elif word.isdigit():
abbr_machine += word
else:
stripped_word = ''.join(char for char in unicodedata.normalize('NFD', word.upper()) if unicodedata.category(char) != 'Mn')
# - use only the first character if the word is too long (> 3 characters)
# - use the whole word if it's not too long (<= 3 characters)
if len(stripped_word) > 3:
stripped_word = stripped_word[0]
abbr_machine += stripped_word
return abbr_machine

View File

@ -66,11 +66,19 @@ class GcodeStartEndFormatter(Formatter):
return "{" + key + "}"
key = key_fragments[0]
try:
return kwargs[str(extruder_nr)][key]
except KeyError:
default_value_str = "{" + key + "}"
value = default_value_str
# "-1" is global stack, and if the setting value exists in the global stack, use it as the fallback value.
if key in kwargs["-1"]:
value = kwargs["-1"]
if key in kwargs[str(extruder_nr)]:
value = kwargs[str(extruder_nr)][key]
if value == default_value_str:
Logger.log("w", "Unable to replace '%s' placeholder in start/end g-code", key)
return "{" + key + "}"
return value
## Job class that builds up the message of scene data to send to CuraEngine.

View File

@ -93,6 +93,11 @@ class FirmwareUpdateCheckerJob(Job):
current_version = self.getCurrentVersion()
# This case indicates that was an error checking the version.
# It happens for instance when not connected to internet.
if current_version == self.ZERO_VERSION:
return
# If it is the first time the version is checked, the checked_version is ""
setting_key_str = getSettingsKeyForMachine(machine_id)
checked_version = Version(Application.getInstance().getPreferences().getValue(setting_key_str))

View File

@ -55,14 +55,14 @@ class PostProcessingPlugin(QObject, Extension):
def selectedScriptDefinitionId(self) -> Optional[str]:
try:
return self._script_list[self._selected_script_index].getDefinitionId()
except:
except IndexError:
return ""
@pyqtProperty(str, notify=selectedIndexChanged)
def selectedScriptStackId(self) -> Optional[str]:
try:
return self._script_list[self._selected_script_index].getStackId()
except:
except IndexError:
return ""
## Execute all post-processing scripts on the gcode.

View File

@ -1,10 +1,14 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
import QtQuick.Controls 2.3
import UM 1.3 as UM
import Cura 1.1 as Cura
import QtGraphicalEffects 1.0 // For the dropshadow
Item
{
@ -24,14 +28,14 @@ Item
Item
{
anchors.horizontalCenter: parent.horizontalCenter
width: openFileButtonBackground.width + itemRow.width + UM.Theme.getSize("default_margin").width
width: openFileButton.width + itemRow.width + UM.Theme.getSize("default_margin").width
height: parent.height
RowLayout
{
id: itemRow
anchors.left: openFileButtonBackground.right
anchors.left: openFileButton.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
width: Math.round(0.9 * prepareMenu.width)
@ -41,7 +45,7 @@ Item
Cura.MachineSelector
{
id: machineSelection
z: openFileButtonBackground.z - 1 //Ensure that the tooltip of the open file button stays above the item row.
z: openFileButton.z - 1 //Ensure that the tooltip of the open file button stays above the item row.
headerCornerSide: Cura.RoundedRectangle.Direction.Left
Layout.minimumWidth: UM.Theme.getSize("machine_selector_widget").width
Layout.maximumWidth: UM.Theme.getSize("machine_selector_widget").width
@ -83,24 +87,53 @@ Item
}
}
Rectangle
Button
{
id: openFileButtonBackground
id: openFileButton
height: UM.Theme.getSize("stage_menu").height
width: UM.Theme.getSize("stage_menu").height
onClicked: Cura.Actions.open.trigger()
hoverEnabled: true
radius: UM.Theme.getSize("default_radius").width
color: UM.Theme.getColor("toolbar_background")
Button
contentItem: Item
{
id: openFileButton
text: catalog.i18nc("@action:button", "Open File")
iconSource: UM.Theme.getIcon("load")
style: UM.Theme.styles.toolbar_button
tooltip: ""
action: Cura.Actions.open
anchors.centerIn: parent
anchors.fill: parent
UM.RecolorImage
{
id: buttonIcon
anchors.centerIn: parent
source: UM.Theme.getIcon("load")
width: UM.Theme.getSize("button_icon").width
height: UM.Theme.getSize("button_icon").height
color: UM.Theme.getColor("toolbar_button_text")
sourceSize.width: width
sourceSize.height: height
}
}
background: Rectangle
{
id: background
height: UM.Theme.getSize("stage_menu").height
width: UM.Theme.getSize("stage_menu").height
radius: UM.Theme.getSize("default_radius").width
color: openFileButton.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button")
}
DropShadow
{
id: shadow
// Don't blur the shadow
radius: 0
anchors.fill: background
source: background
verticalOffset: 2
visible: true
color: UM.Theme.getColor("action_button_shadow")
// Should always be drawn behind the background.
z: background.z - 1
}
}
}

View File

@ -29,80 +29,12 @@ Item
anchors.centerIn: parent
height: parent.height
Cura.ExpandableComponent
Cura.ViewsSelector
{
id: viewSelector
iconSource: expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left")
id: viewsSelector
height: parent.height
width: UM.Theme.getSize("views_selector").width
headerCornerSide: Cura.RoundedRectangle.Direction.Left
property var viewModel: UM.ViewModel { }
property var activeView:
{
for (var i = 0; i < viewModel.rowCount(); i++)
{
if (viewModel.items[i].active)
{
return viewModel.items[i]
}
}
return null
}
Component.onCompleted:
{
// Nothing was active, so just return the first one (the list is sorted by priority, so the most
// important one should be returned)
if (activeView == null)
{
UM.Controller.setActiveView(viewModel.getItem(0).id)
}
}
headerItem: Label
{
text: viewSelector.activeView ? viewSelector.activeView.name : ""
verticalAlignment: Text.AlignVCenter
height: parent.height
elide: Text.ElideRight
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
}
popupItem: Column
{
id: viewSelectorPopup
width: viewSelector.width - 2 * UM.Theme.getSize("default_margin").width
// For some reason the height/width of the column gets set to 0 if this is not set...
Component.onCompleted:
{
height = implicitHeight
width = viewSelector.width - 2 * UM.Theme.getSize("default_margin").width
}
Repeater
{
id: viewsList
model: viewSelector.viewModel
RoundButton
{
text: name
radius: UM.Theme.getSize("default_radius").width
checkable: true
checked: viewSelector.activeView != null ? viewSelector.activeView.id == id : false
onClicked:
{
viewSelector.togglePopup()
UM.Controller.setActiveView(id)
}
}
}
}
}
// Separator line

View File

@ -6,7 +6,7 @@ import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM
import UM 1.4 as UM
import Cura 1.0 as Cura
Item
@ -55,11 +55,16 @@ Item
}
Button
UM.SimpleButton
{
id: playButton
iconSource: !is_simulation_playing ? "./resources/simulation_resume.svg": "./resources/simulation_pause.svg"
style: UM.Theme.styles.small_tool_button
width: UM.Theme.getSize("small_button").width
height: UM.Theme.getSize("small_button").height
hoverBackgroundColor: UM.Theme.getColor("small_button_hover")
hoverColor: UM.Theme.getColor("small_button_text_hover")
color: UM.Theme.getColor("small_button_text")
iconMargin: 0.5 * UM.Theme.getSize("wide_lining").width
visible: !UM.SimulationView.compatibilityMode
Connections

View File

@ -37,7 +37,7 @@ Item
leftMargin: UM.Theme.getSize("wide_margin").width
topMargin: UM.Theme.getSize("wide_margin").height
}
color: white //Always a white background for image (regardless of theme).
color: "white" //Always a white background for image (regardless of theme).
Image
{
anchors.fill: parent

View File

@ -0,0 +1,43 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
## Base model that maps kwargs to instance attributes.
class BaseModel:
def __init__(self, **kwargs) -> None:
self.__dict__.update(kwargs)
self.validate()
def validate(self) -> None:
pass
## Class representing a material that was fetched from the cluster API.
class ClusterMaterial(BaseModel):
def __init__(self, guid: str, version: int, **kwargs) -> None:
self.guid = guid # type: str
self.version = version # type: int
super().__init__(**kwargs)
def validate(self) -> None:
if not self.guid:
raise ValueError("guid is required on ClusterMaterial")
if not self.version:
raise ValueError("version is required on ClusterMaterial")
## Class representing a local material that was fetched from the container registry.
class LocalMaterial(BaseModel):
def __init__(self, GUID: str, id: str, version: int, **kwargs) -> None:
self.GUID = GUID # type: str
self.id = id # type: str
self.version = version # type: int
super().__init__(**kwargs)
def validate(self) -> None:
if not self.GUID:
raise ValueError("guid is required on LocalMaterial")
if not self.version:
raise ValueError("version is required on LocalMaterial")
if not self.id:
raise ValueError("id is required on LocalMaterial")

View File

@ -1,99 +1,197 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import json
import os
import urllib.parse
from typing import Dict, TYPE_CHECKING, Set
import json #To understand the list of materials from the printer reply.
import os #To walk over material files.
import os.path #To filter on material files.
from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest #To listen to the reply from the printer.
from typing import Any, Dict, Set, TYPE_CHECKING
import urllib.parse #For getting material IDs from their file names.
from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
from UM.Job import Job #The interface we're implementing.
from UM.Application import Application
from UM.Job import Job
from UM.Logger import Logger
from UM.MimeTypeDatabase import MimeTypeDatabase #To strip the extensions of the material profile files.
from UM.MimeTypeDatabase import MimeTypeDatabase
from UM.Resources import Resources
from UM.Settings.ContainerRegistry import ContainerRegistry #To find the GUIDs of materials.
from cura.CuraApplication import CuraApplication #For the resource types.
from cura.CuraApplication import CuraApplication
# Absolute imports don't work in plugins
from .Models import ClusterMaterial, LocalMaterial
if TYPE_CHECKING:
from .ClusterUM3OutputDevice import ClusterUM3OutputDevice
## Asynchronous job to send material profiles to the printer.
#
# This way it won't freeze up the interface while sending those materials.
class SendMaterialJob(Job):
def __init__(self, device: "ClusterUM3OutputDevice") -> None:
super().__init__()
self.device = device #type: ClusterUM3OutputDevice
self.device = device # type: ClusterUM3OutputDevice
## Send the request to the printer and register a callback
def run(self) -> None:
self.device.get("materials/", on_finished = self.sendMissingMaterials)
self.device.get("materials/", on_finished = self._onGetRemoteMaterials)
def sendMissingMaterials(self, reply: QNetworkReply) -> None:
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: #Got an error from the HTTP request.
Logger.log("e", "Couldn't request current material storage on printer. Not syncing materials.")
## Process the materials reply from the printer.
#
# \param reply The reply from the printer, a json file.
def _onGetRemoteMaterials(self, reply: QNetworkReply) -> None:
# Got an error from the HTTP request. If we did not receive a 200 something happened.
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
Logger.log("e", "Error fetching materials from printer: %s", reply.errorString())
return
remote_materials_list = reply.readAll().data().decode("utf-8")
try:
remote_materials_list = json.loads(remote_materials_list)
except json.JSONDecodeError:
Logger.log("e", "Request material storage on printer: I didn't understand the printer's answer.")
return
try:
remote_materials_by_guid = {material["guid"]: material for material in remote_materials_list} #Index by GUID.
except KeyError:
Logger.log("e", "Request material storage on printer: Printer's answer was missing GUIDs.")
# Collect materials from the printer's reply and send the missing ones if needed.
remote_materials_by_guid = self._parseReply(reply)
if remote_materials_by_guid:
self._sendMissingMaterials(remote_materials_by_guid)
## Determine which materials should be updated and send them to the printer.
#
# \param remote_materials_by_guid The remote materials by GUID.
def _sendMissingMaterials(self, remote_materials_by_guid: Dict[str, ClusterMaterial]) -> None:
# Collect local materials
local_materials_by_guid = self._getLocalMaterials()
if len(local_materials_by_guid) == 0:
Logger.log("d", "There are no local materials to synchronize with the printer.")
return
container_registry = ContainerRegistry.getInstance()
local_materials_list = filter(lambda material: ("GUID" in material and "version" in material and "id" in material), container_registry.findContainersMetadata(type = "material"))
local_materials_by_guid = {material["GUID"]: material for material in local_materials_list if material["id"] == material["base_file"]}
for material in local_materials_list: #For each GUID get the material with the highest version number.
try:
if int(material["version"]) > local_materials_by_guid[material["GUID"]]["version"]:
local_materials_by_guid[material["GUID"]] = material
except ValueError:
Logger.log("e", "Material {material_id} has invalid version number {number}.".format(material_id = material["id"], number = material["version"]))
continue
# Find out what materials are new or updated and must be sent to the printer
material_ids_to_send = self._determineMaterialsToSend(local_materials_by_guid, remote_materials_by_guid)
if len(material_ids_to_send) == 0:
Logger.log("d", "There are no remote materials to update.")
return
materials_to_send = set() #type: Set[Dict[str, Any]]
for guid, material in local_materials_by_guid.items():
if guid not in remote_materials_by_guid:
materials_to_send.add(material["id"])
continue
try:
if int(material["version"]) > remote_materials_by_guid[guid]["version"]:
materials_to_send.add(material["id"])
continue
except KeyError:
Logger.log("e", "Current material storage on printer was an invalid reply (missing version).")
return
# Send materials to the printer
self._sendMaterials(material_ids_to_send)
for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.MaterialInstanceContainer):
## From the local and remote materials, determine which ones should be synchronized.
#
# Makes a Set of id's containing only the id's of the materials that are not on the printer yet or the ones that
# are newer in Cura.
#
# \param local_materials The local materials by GUID.
# \param remote_materials The remote materials by GUID.
@staticmethod
def _determineMaterialsToSend(local_materials: Dict[str, LocalMaterial],
remote_materials: Dict[str, ClusterMaterial]) -> Set[str]:
return {
material.id
for guid, material in local_materials.items()
if guid not in remote_materials or material.version > remote_materials[guid].version
}
## Send the materials to the printer.
#
# The given materials will be loaded from disk en sent to to printer.
# The given id's will be matched with filenames of the locally stored materials.
#
# \param materials_to_send A set with id's of materials that must be sent.
def _sendMaterials(self, materials_to_send: Set[str]) -> None:
file_paths = Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.MaterialInstanceContainer)
# Find all local material files and send them if needed.
for file_path in file_paths:
try:
mime_type = MimeTypeDatabase.getMimeTypeForFile(file_path)
except MimeTypeDatabase.MimeTypeNotFoundError:
continue #Not the sort of file we'd like to send then.
_, file_name = os.path.split(file_path)
material_id = urllib.parse.unquote_plus(mime_type.stripExtension(file_name))
if material_id not in materials_to_send:
continue
parts = []
with open(file_path, "rb") as f:
parts.append(self.device._createFormPart("name=\"file\"; filename=\"{file_name}\"".format(file_name = file_name), f.read()))
signature_file_path = file_path + ".sig"
if os.path.exists(signature_file_path):
_, signature_file_name = os.path.split(signature_file_path)
with open(signature_file_path, "rb") as f:
parts.append(self.device._createFormPart("name=\"signature_file\"; filename=\"{file_name}\"".format(file_name = signature_file_name), f.read()))
file_name = os.path.basename(file_path)
material_id = urllib.parse.unquote_plus(mime_type.stripExtension(file_name))
if material_id not in materials_to_send:
# If the material does not have to be sent we skip it.
continue
Logger.log("d", "Syncing material {material_id} with cluster.".format(material_id = material_id))
self.device.postFormWithParts(target = "materials/", parts = parts, on_finished = self.sendingFinished)
self._sendMaterialFile(file_path, file_name, material_id)
def sendingFinished(self, reply: QNetworkReply):
## Send a single material file to the printer.
#
# Also add the material signature file if that is available.
#
# \param file_path The path of the material file.
# \param file_name The name of the material file.
# \param material_id The ID of the material in the file.
def _sendMaterialFile(self, file_path: str, file_name: str, material_id: str) -> None:
parts = []
# Add the material file.
with open(file_path, "rb") as f:
parts.append(self.device.createFormPart("name=\"file\"; filename=\"{file_name}\""
.format(file_name = file_name), f.read()))
# Add the material signature file if needed.
signature_file_path = "{}.sig".format(file_path)
if os.path.exists(signature_file_path):
signature_file_name = os.path.basename(signature_file_path)
with open(signature_file_path, "rb") as f:
parts.append(self.device.createFormPart("name=\"signature_file\"; filename=\"{file_name}\""
.format(file_name = signature_file_name), f.read()))
Logger.log("d", "Syncing material {material_id} with cluster.".format(material_id = material_id))
self.device.postFormWithParts(target = "materials/", parts = parts, on_finished = self.sendingFinished)
## Check a reply from an upload to the printer and log an error when the call failed
@staticmethod
def sendingFinished(reply: QNetworkReply) -> None:
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
Logger.log("e", "Received error code from printer when syncing material: {code}".format(code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)))
Logger.log("e", reply.readAll().data().decode("utf-8"))
Logger.log("e", "Received error code from printer when syncing material: {code}, {text}".format(
code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute),
text = reply.errorString()
))
## Parse the reply from the printer
#
# Parses the reply to a "/materials" request to the printer
#
# \return a dictionary of ClusterMaterial objects by GUID
# \throw KeyError Raised when on of the materials does not include a valid guid
@classmethod
def _parseReply(cls, reply: QNetworkReply) -> Dict[str, ClusterMaterial]:
try:
remote_materials = json.loads(reply.readAll().data().decode("utf-8"))
return {material["guid"]: ClusterMaterial(**material) for material in remote_materials}
except UnicodeDecodeError:
Logger.log("e", "Request material storage on printer: I didn't understand the printer's answer.")
except json.JSONDecodeError:
Logger.log("e", "Request material storage on printer: I didn't understand the printer's answer.")
except ValueError:
Logger.log("e", "Request material storage on printer: Printer's answer had an incorrect value.")
except TypeError:
Logger.log("e", "Request material storage on printer: Printer's answer was missing a required value.")
## Retrieves a list of local materials
#
# Only the new newest version of the local materials is returned
#
# \return a dictionary of LocalMaterial objects by GUID
def _getLocalMaterials(self) -> Dict[str, LocalMaterial]:
result = {} # type: Dict[str, LocalMaterial]
container_registry = Application.getInstance().getContainerRegistry()
material_containers = container_registry.findContainersMetadata(type = "material")
# Find the latest version of all material containers in the registry.
for material in material_containers:
try:
# material version must be an int
material["version"] = int(material["version"])
# Create a new local material
local_material = LocalMaterial(**material)
if local_material.GUID not in result or \
local_material.version > result.get(local_material.GUID).version:
result[local_material.GUID] = local_material
except KeyError:
Logger.logException("w", "Local material {} has missing values.".format(material["id"]))
except ValueError:
Logger.logException("w", "Local material {} has invalid values.".format(material["id"]))
except TypeError:
Logger.logException("w", "Local material {} has invalid values.".format(material["id"]))
return result

View File

@ -1,4 +1,4 @@
# Copyright (c) 2017 Ultimaker B.V.
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
@ -325,13 +325,12 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
## Handler for zeroConf detection.
# Return True or False indicating if the process succeeded.
# Note that this function can take over 3 seconds to complete. Be carefull calling it from the main thread.
# Note that this function can take over 3 seconds to complete. Be careful
# calling it from the main thread.
def _onServiceChanged(self, zero_conf, service_type, name, state_change):
if state_change == ServiceStateChange.Added:
Logger.log("d", "Bonjour service added: %s" % name)
# First try getting info from zero-conf cache
info = ServiceInfo(service_type, name, properties={})
info = ServiceInfo(service_type, name, properties = {})
for record in zero_conf.cache.entries_with_name(name.lower()):
info.update_record(zero_conf, time(), record)

View File

@ -0,0 +1,190 @@
# Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import io
import json
from unittest import TestCase, mock
from unittest.mock import patch, call
from PyQt5.QtCore import QByteArray
from UM.MimeTypeDatabase import MimeType
from UM.Application import Application
from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob
@patch("builtins.open", lambda _, __: io.StringIO("<xml></xml>"))
@patch("UM.MimeTypeDatabase.MimeTypeDatabase.getMimeTypeForFile",
lambda _: MimeType(name = "application/x-ultimaker-material-profile", comment = "Ultimaker Material Profile",
suffixes = ["xml.fdm_material"]))
@patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: ["/materials/generic_pla_white.xml.fdm_material"])
@patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice")
@patch("PyQt5.QtNetwork.QNetworkReply")
class TestSendMaterialJob(TestCase):
_LOCAL_MATERIAL_WHITE = {"type": "material", "status": "unknown", "id": "generic_pla_white",
"base_file": "generic_pla_white", "setting_version": "5", "name": "White PLA",
"brand": "Generic", "material": "PLA", "color_name": "White",
"GUID": "badb0ee7-87c8-4f3f-9398-938587b67dce", "version": "1", "color_code": "#ffffff",
"description": "Test PLA White", "adhesion_info": "Use glue.", "approximate_diameter": "3",
"properties": {"density": "1.00", "diameter": "2.85", "weight": "750"},
"definition": "fdmprinter", "compatible": True}
_LOCAL_MATERIAL_BLACK = {"type": "material", "status": "unknown", "id": "generic_pla_black",
"base_file": "generic_pla_black", "setting_version": "5", "name": "Yellow CPE",
"brand": "Ultimaker", "material": "CPE", "color_name": "Black",
"GUID": "5fbb362a-41f9-4818-bb43-15ea6df34aa4", "version": "1", "color_code": "#000000",
"description": "Test PLA Black", "adhesion_info": "Use glue.", "approximate_diameter": "3",
"properties": {"density": "1.01", "diameter": "2.85", "weight": "750"},
"definition": "fdmprinter", "compatible": True}
_REMOTE_MATERIAL_WHITE = {
"guid": "badb0ee7-87c8-4f3f-9398-938587b67dce",
"material": "PLA",
"brand": "Generic",
"version": 1,
"color": "White",
"density": 1.00
}
_REMOTE_MATERIAL_BLACK = {
"guid": "5fbb362a-41f9-4818-bb43-15ea6df34aa4",
"material": "PLA",
"brand": "Generic",
"version": 2,
"color": "Black",
"density": 1.00
}
def test_run(self, device_mock, reply_mock):
job = SendMaterialJob(device_mock)
job.run()
# We expect the materials endpoint to be called when the job runs.
device_mock.get.assert_called_with("materials/", on_finished = job._onGetRemoteMaterials)
def test__onGetRemoteMaterials_withFailedRequest(self, reply_mock, device_mock):
reply_mock.attribute.return_value = 404
job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock)
# We expect the device not to be called for any follow up.
self.assertEqual(0, device_mock.createFormPart.call_count)
def test__onGetRemoteMaterials_withWrongEncoding(self, reply_mock, device_mock):
reply_mock.attribute.return_value = 200
reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("cp500"))
job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock)
# Given that the parsing fails we do no expect the device to be called for any follow up.
self.assertEqual(0, device_mock.createFormPart.call_count)
def test__onGetRemoteMaterials_withBadJsonAnswer(self, reply_mock, device_mock):
reply_mock.attribute.return_value = 200
reply_mock.readAll.return_value = QByteArray(b"Six sick hicks nick six slick bricks with picks and sticks.")
job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock)
# Given that the parsing fails we do no expect the device to be called for any follow up.
self.assertEqual(0, device_mock.createFormPart.call_count)
def test__onGetRemoteMaterials_withMissingGuidInRemoteMaterial(self, reply_mock, device_mock):
reply_mock.attribute.return_value = 200
remote_material_without_guid = self._REMOTE_MATERIAL_WHITE.copy()
del remote_material_without_guid["guid"]
reply_mock.readAll.return_value = QByteArray(json.dumps([remote_material_without_guid]).encode("ascii"))
job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock)
# Given that parsing fails we do not expect the device to be called for any follow up.
self.assertEqual(0, device_mock.createFormPart.call_count)
@patch("cura.Settings.CuraContainerRegistry")
@patch("UM.Application")
def test__onGetRemoteMaterials_withInvalidVersionInLocalMaterial(self, application_mock, container_registry_mock,
reply_mock, device_mock):
reply_mock.attribute.return_value = 200
reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
localMaterialWhiteWithInvalidVersion = self._LOCAL_MATERIAL_WHITE.copy()
localMaterialWhiteWithInvalidVersion["version"] = "one"
container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithInvalidVersion]
application_mock.getContainerRegistry.return_value = container_registry_mock
with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock)
self.assertEqual(0, device_mock.createFormPart.call_count)
@patch("cura.Settings.CuraContainerRegistry")
@patch("UM.Application")
def test__onGetRemoteMaterials_withNoUpdate(self, application_mock, container_registry_mock, reply_mock,
device_mock):
application_mock.getContainerRegistry.return_value = container_registry_mock
device_mock.createFormPart.return_value = "_xXx_"
container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE]
reply_mock.attribute.return_value = 200
reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock)
self.assertEqual(0, device_mock.createFormPart.call_count)
self.assertEqual(0, device_mock.postFormWithParts.call_count)
@patch("cura.Settings.CuraContainerRegistry")
@patch("UM.Application")
def test__onGetRemoteMaterials_withUpdatedMaterial(self, application_mock, container_registry_mock, reply_mock,
device_mock):
application_mock.getContainerRegistry.return_value = container_registry_mock
device_mock.createFormPart.return_value = "_xXx_"
localMaterialWhiteWithHigherVersion = self._LOCAL_MATERIAL_WHITE.copy()
localMaterialWhiteWithHigherVersion["version"] = "2"
container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithHigherVersion]
reply_mock.attribute.return_value = 200
reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock)
self.assertEqual(1, device_mock.createFormPart.call_count)
self.assertEqual(1, device_mock.postFormWithParts.call_count)
self.assertEquals(
[call.createFormPart("name=\"file\"; filename=\"generic_pla_white.xml.fdm_material\"", "<xml></xml>"),
call.postFormWithParts(target = "materials/", parts = ["_xXx_"], on_finished = job.sendingFinished)],
device_mock.method_calls)
@patch("cura.Settings.CuraContainerRegistry")
@patch("UM.Application")
def test__onGetRemoteMaterials_withNewMaterial(self, application_mock, container_registry_mock, reply_mock,
device_mock):
application_mock.getContainerRegistry.return_value = container_registry_mock
device_mock.createFormPart.return_value = "_xXx_"
container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE,
self._LOCAL_MATERIAL_BLACK]
reply_mock.attribute.return_value = 200
reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_BLACK]).encode("ascii"))
with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock)
self.assertEqual(1, device_mock.createFormPart.call_count)
self.assertEqual(1, device_mock.postFormWithParts.call_count)
self.assertEquals(
[call.createFormPart("name=\"file\"; filename=\"generic_pla_white.xml.fdm_material\"", "<xml></xml>"),
call.postFormWithParts(target = "materials/", parts = ["_xXx_"], on_finished = job.sendingFinished)],
device_mock.method_calls)

View File

@ -3,6 +3,7 @@
from UM.Job import Job
from UM.Logger import Logger
from plugins.USBPrinting.avr_isp import ispBase
from .avr_isp.stk500v2 import Stk500v2
@ -14,12 +15,12 @@ from serial import Serial, SerialException
# It tries a pre-set list of baud rates. All these baud rates are validated by requesting the temperature a few times
# and checking if the results make sense. If getResult() is not None, it was able to find a correct baud rate.
class AutoDetectBaudJob(Job):
def __init__(self, serial_port):
def __init__(self, serial_port: int) -> None:
super().__init__()
self._serial_port = serial_port
self._all_baud_rates = [115200, 250000, 230400, 57600, 38400, 19200, 9600]
def run(self):
def run(self) -> None:
Logger.log("d", "Auto detect baud rate started.")
wait_response_timeouts = [3, 15, 30]
wait_bootloader_times = [1.5, 5, 15]
@ -32,7 +33,7 @@ class AutoDetectBaudJob(Job):
try:
programmer.connect(self._serial_port)
serial = programmer.leaveISP()
except:
except ispBase.IspError:
programmer.close()
for retry in range(tries):
@ -58,7 +59,7 @@ class AutoDetectBaudJob(Job):
# We already have a serial connection, just change the baud rate.
try:
serial.baudrate = baud_rate
except:
except ValueError:
continue
sleep(wait_bootloader) # Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number
successful_responses = 0
@ -81,5 +82,5 @@ class AutoDetectBaudJob(Job):
return
serial.write(b"M105\n")
sleep(15) # Give the printer some time to init and try again.
sleep(15) # Give the printer some time to init and try again.
self.setResult(None) # Unable to detect the correct baudrate.

View File

@ -0,0 +1,96 @@
{
"name": "Alfawise U20",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Samuel Pinches",
"manufacturer": "Alfawise",
"file_formats": "text/x-gcode",
"preferred_quality_type": "fine",
"machine_extruder_trains":
{
"0": "alfawise_u20_extruder_0"
}
},
"overrides": {
"machine_name": {
"default_value": "Alfawise U20"
},
"machine_start_gcode": {
"default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nM140 S0 ;turn off bed heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 ;move to the X-axis origin (Home)\nG0 Y280 F600 ;bring the bed to the front for easy print removal\nM84 ;turn off stepper motors\n; -- end of END GCODE --"
},
"machine_width": {
"default_value": 300
},
"machine_height": {
"default_value": 400
},
"machine_depth": {
"default_value": 300
},
"machine_heated_bed": {
"default_value": true
},
"machine_center_is_zero": {
"default_value": false
},
"gantry_height": {
"default_value": 10
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},
"material_diameter": {
"default_value": 1.75
},
"material_print_temperature": {
"default_value": 210
},
"material_bed_temperature": {
"default_value": 50
},
"layer_height": {
"default_value": 0.15
},
"layer_height_0": {
"default_value": 0.2
},
"wall_thickness": {
"default_value": 1.2
},
"speed_print": {
"default_value": 40
},
"speed_infill": {
"default_value": 40
},
"speed_wall": {
"default_value": 35
},
"speed_topbottom": {
"default_value": 35
},
"speed_travel": {
"default_value": 120
},
"speed_layer_0": {
"default_value": 20
},
"support_enable": {
"default_value": true
},
"retraction_enable": {
"default_value": true
},
"retraction_amount": {
"default_value": 5
},
"retraction_speed": {
"default_value": 45
}
}
}

View File

@ -0,0 +1,92 @@
{
"id": "BIBO2 dual",
"version": 2,
"name": "BIBO2 dual",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "na",
"manufacturer": "BIBO",
"category": "Other",
"file_formats": "text/x-gcode",
"has_materials": true,
"machine_extruder_trains": {
"0": "bibo2_dual_extruder_0",
"1": "bibo2_dual_extruder_1"
},
"first_start_actions": [
"MachineSettingsAction"
]
},
"overrides": {
"machine_name": {
"default_value": "BIBO2 dual"
},
"machine_width": {
"default_value": 214
},
"machine_height": {
"default_value": 160
},
"machine_depth": {
"default_value": 186
},
"machine_center_is_zero": {
"default_value": true
},
"machine_heated_bed": {
"default_value": true
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_head_with_fans_polygon": {
"default_value": [
[
-68.18,
64.63
],
[
-68.18,
-47.38
],
[
35.18,
64.63
],
[
35.18,
-47.38
]
]
},
"gantry_height": {
"default_value": 12
},
"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\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z2.0 F400 ;move the platform down 15mm\nT0\nG92 E0\nG28\nG1 Y0 F1200 E0\nG92 E0\nM117 BIBO Printing..."
},
"machine_end_gcode": {
"default_value": ";End GCode\nM104 T0 S0 ;extruder heater off\nM104 T1 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91\nG1 Z1 F100 ;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-2 X-20 Y-20 F300 ;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"
},
"machine_extruder_count": {
"default_value": 2
},
"prime_tower_position_x": {
"default_value": 50
},
"prime_tower_position_y": {
"default_value": 50
}
}
}

View File

@ -0,0 +1,96 @@
{
"name": "Cocoon Create ModelMaker & Wanhao Duplicator i3 Mini",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Samuel Pinches",
"manufacturer": "Cocoon Create / Wanhao",
"file_formats": "text/x-gcode",
"preferred_quality_type": "fine",
"machine_extruder_trains":
{
"0": "cocoon_create_modelmaker_extruder_0"
}
},
"overrides": {
"machine_name": {
"default_value": "Cocoon Create ModelMaker & Wanhao Duplicator i3 Mini"
},
"machine_start_gcode": {
"default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 Y0 ;move to the XY-axis origin (Home)\nM84 ;turn off stepper motors\n; -- end of END GCODE --"
},
"machine_width": {
"default_value": 120
},
"machine_height": {
"default_value": 100
},
"machine_depth": {
"default_value": 135
},
"machine_heated_bed": {
"default_value": false
},
"machine_center_is_zero": {
"default_value": false
},
"gantry_height": {
"default_value": 10
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},
"material_diameter": {
"default_value": 1.75
},
"material_print_temperature": {
"default_value": 220
},
"layer_height": {
"default_value": 0.15
},
"layer_height_0": {
"default_value": 0.2
},
"wall_thickness": {
"default_value": 1.2
},
"top_bottom_thickness": {
"default_value": 0.6
},
"speed_print": {
"default_value": 40
},
"speed_infill": {
"default_value": 40
},
"speed_wall": {
"default_value": 35
},
"speed_topbottom": {
"default_value": 35
},
"speed_travel": {
"default_value": 70
},
"speed_layer_0": {
"default_value": 20
},
"support_enable": {
"default_value": true
},
"retraction_enable": {
"default_value": true
},
"retraction_amount": {
"default_value": 7
},
"retraction_speed": {
"default_value": 40
}
}
}

View File

@ -0,0 +1,96 @@
{
"name": "JGAurora A1",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Samuel Pinches",
"manufacturer": "JGAurora",
"file_formats": "text/x-gcode",
"preferred_quality_type": "fine",
"machine_extruder_trains":
{
"0": "jgaurora_a1_extruder_0"
}
},
"overrides": {
"machine_name": {
"default_value": "JGAurora A1"
},
"machine_start_gcode": {
"default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nM420 S1 ;turn on mesh bed levelling if enabled in firmware\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nM140 S0 ;turn off bed heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 ;move to the X-axis origin (Home)\nG0 Y280 F600 ;bring the bed to the front for easy print removal\nM84 ;turn off stepper motors\n; -- end of END GCODE --"
},
"machine_width": {
"default_value": 300
},
"machine_height": {
"default_value": 300
},
"machine_depth": {
"default_value": 300
},
"machine_heated_bed": {
"default_value": true
},
"machine_center_is_zero": {
"default_value": false
},
"gantry_height": {
"default_value": 10
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},
"material_diameter": {
"default_value": 1.75
},
"material_print_temperature": {
"default_value": 215
},
"material_bed_temperature": {
"default_value": 67
},
"layer_height": {
"default_value": 0.15
},
"layer_height_0": {
"default_value": 0.12
},
"wall_thickness": {
"default_value": 1.2
},
"speed_print": {
"default_value": 40
},
"speed_infill": {
"default_value": 40
},
"speed_wall": {
"default_value": 35
},
"speed_topbottom": {
"default_value": 35
},
"speed_travel": {
"default_value": 120
},
"speed_layer_0": {
"default_value": 12
},
"support_enable": {
"default_value": true
},
"retraction_enable": {
"default_value": true
},
"retraction_amount": {
"default_value": 6
},
"retraction_speed": {
"default_value": 40
}
}
}

View File

@ -0,0 +1,98 @@
{
"name": "JGAurora A5 & A5S",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Samuel Pinches",
"manufacturer": "JGAurora",
"file_formats": "text/x-gcode",
"platform": "jgaurora_a5.stl",
"platform_offset": [-242, -101, 273],
"preferred_quality_type": "fine",
"machine_extruder_trains":
{
"0": "jgaurora_a5_extruder_0"
}
},
"overrides": {
"machine_name": {
"default_value": "JGAurora A5 & A5S"
},
"machine_start_gcode": {
"default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nM420 S1 ;turn on mesh bed levelling if enabled in firmware\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nM140 S0 ;turn off bed heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 ;move to the X-axis origin (Home)\nG0 Y280 F600 ;bring the bed to the front for easy print removal\nM84 ;turn off stepper motors\n; -- end of END GCODE --"
},
"machine_width": {
"default_value": 300
},
"machine_height": {
"default_value": 320
},
"machine_depth": {
"default_value": 300
},
"machine_heated_bed": {
"default_value": true
},
"machine_center_is_zero": {
"default_value": false
},
"gantry_height": {
"default_value": 10
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},
"material_diameter": {
"default_value": 1.75
},
"material_print_temperature": {
"default_value": 215
},
"material_bed_temperature": {
"default_value": 67
},
"layer_height": {
"default_value": 0.15
},
"layer_height_0": {
"default_value": 0.12
},
"wall_thickness": {
"default_value": 1.2
},
"speed_print": {
"default_value": 40
},
"speed_infill": {
"default_value": 40
},
"speed_wall": {
"default_value": 35
},
"speed_topbottom": {
"default_value": 35
},
"speed_travel": {
"default_value": 120
},
"speed_layer_0": {
"default_value": 12
},
"support_enable": {
"default_value": true
},
"retraction_enable": {
"default_value": true
},
"retraction_amount": {
"default_value": 8
},
"retraction_speed": {
"default_value": 45
}
}
}

View File

@ -0,0 +1,96 @@
{
"name": "JGAurora Z-603S",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Samuel Pinches",
"manufacturer": "JGAurora",
"file_formats": "text/x-gcode",
"preferred_quality_type": "fine",
"machine_extruder_trains":
{
"0": "jgaurora_z_603s_extruder_0"
}
},
"overrides": {
"machine_name": {
"default_value": "JGAurora Z-603S"
},
"machine_start_gcode": {
"default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nM420 S1 ;turn on mesh bed levelling if enabled in firmware\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nM140 S0 ;turn off bed heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 ;move to the X-axis origin (Home)\nG0 Y280 F600 ;bring the bed to the front for easy print removal\nM84 ;turn off stepper motors\n; -- end of END GCODE --"
},
"machine_width": {
"default_value": 280
},
"machine_height": {
"default_value": 175
},
"machine_depth": {
"default_value": 180
},
"machine_heated_bed": {
"default_value": true
},
"machine_center_is_zero": {
"default_value": false
},
"gantry_height": {
"default_value": 10
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},
"material_diameter": {
"default_value": 1.75
},
"material_print_temperature": {
"default_value": 210
},
"material_bed_temperature": {
"default_value": 55
},
"layer_height": {
"default_value": 0.15
},
"layer_height_0": {
"default_value": 0.2
},
"wall_thickness": {
"default_value": 1.2
},
"speed_print": {
"default_value": 60
},
"speed_infill": {
"default_value": 60
},
"speed_wall": {
"default_value": 30
},
"speed_topbottom": {
"default_value": 45
},
"speed_travel": {
"default_value": 125
},
"speed_layer_0": {
"default_value": 20
},
"support_enable": {
"default_value": true
},
"retraction_enable": {
"default_value": true
},
"retraction_amount": {
"default_value": 5
},
"retraction_speed": {
"default_value": 50
}
}
}

View File

@ -39,10 +39,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..."
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
}
}
}

View File

@ -42,10 +42,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..."
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
}
}
}

View File

@ -39,10 +39,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..."
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
}
}
}

View File

@ -42,10 +42,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..."
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
}
}
}

View File

@ -39,10 +39,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..."
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
}
}
}

View File

@ -39,10 +39,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..."
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
}
}
}

View File

@ -39,10 +39,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..."
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
}
}
}

View File

@ -39,10 +39,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..."
"default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
"default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning"
}
}
}

View File

@ -0,0 +1,16 @@
{
"id": "alfawise_u20_extruder_0",
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "alfawise_u20",
"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,46 @@
{
"id": "BIBO1",
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "BIBO2 dual",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_offset_x": {
"default_value": 0.0
},
"machine_nozzle_offset_y": {
"default_value": 0.0
},
"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"
}
}
}

View File

@ -0,0 +1,46 @@
{
"id": "BIBO2",
"version": 2,
"name": "Extruder 2",
"inherits": "fdmextruder",
"metadata": {
"machine": "BIBO2 dual",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_offset_x": {
"default_value": 0.0
},
"machine_nozzle_offset_y": {
"default_value": 0.0
},
"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"
}
}
}

View File

@ -0,0 +1,16 @@
{
"id": "cocoon_create_modelmaker_extruder_0",
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "cocoon_create_modelmaker",
"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,16 @@
{
"id": "jgaurora_a1_extruder_0",
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "jgaurora_a1",
"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,16 @@
{
"id": "jgaurora_a5_extruder_0",
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "jgaurora_a5",
"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,16 @@
{
"id": "jgaurora_z_603s_extruder_0",
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "jgaurora_z_603s",
"position": "0"
},
"overrides": {
"extruder_nr": { "default_value": 0 },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 }
}
}

Binary file not shown.

View File

@ -11,20 +11,16 @@ Row
{
spacing: UM.Theme.getSize("default_margin").width
Cura.ActionButton
Cura.SecondaryButton
{
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Create account")
color: UM.Theme.getColor("secondary")
hoverColor: UM.Theme.getColor("secondary")
textColor: UM.Theme.getColor("main_window_header_button_text_active")
textHoverColor: UM.Theme.getColor("main_window_header_button_text_active")
onClicked: Qt.openUrlExternally("https://account.ultimaker.com/app/create")
fixedWidthMode: true
}
Cura.ActionButton
Cura.PrimaryButton
{
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height

View File

@ -11,20 +11,16 @@ Row
{
spacing: UM.Theme.getSize("default_margin").width
Cura.ActionButton
Cura.SecondaryButton
{
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Manage account")
color: UM.Theme.getColor("secondary")
hoverColor: UM.Theme.getColor("secondary")
textColor: UM.Theme.getColor("main_window_header_button_text_active")
textHoverColor: UM.Theme.getColor("main_window_header_button_text_active")
onClicked: Qt.openUrlExternally("https://account.ultimaker.com")
fixedWidthMode: true
}
Cura.ActionButton
Cura.PrimaryButton
{
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height

View File

@ -3,28 +3,35 @@
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0 // For the dropshadow
import UM 1.1 as UM
Button
{
id: button
property alias cursorShape: mouseArea.cursorShape
property alias iconSource: buttonIcon.source
property alias iconSourceRight: buttonIconRight.source
property alias textFont: buttonText.font
property alias cornerRadius: backgroundRect.radius
property alias tooltip: tooltip.text
property var color: UM.Theme.getColor("primary")
property var hoverColor: UM.Theme.getColor("primary_hover")
property var disabledColor: color
property var textColor: UM.Theme.getColor("button_text")
property var textHoverColor: UM.Theme.getColor("button_text_hover")
property var textDisabledColor: textColor
property var outlineColor: color
property var outlineHoverColor: hoverColor
property var outlineDisabledColor: outlineColor
property color color: UM.Theme.getColor("primary")
property color hoverColor: UM.Theme.getColor("primary_hover")
property color disabledColor: color
property color textColor: UM.Theme.getColor("button_text")
property color textHoverColor: textColor
property color textDisabledColor: textColor
property color outlineColor: color
property color outlineHoverColor: hoverColor
property color outlineDisabledColor: outlineColor
hoverEnabled: true
property alias shadowColor: shadow.color
property alias shadowEnabled: shadow.visible
// This property is used to indicate whether the button has a fixed width or the width would depend on the contents
// Be careful when using fixedWidthMode, the translated texts can be too long that they won't fit. In any case,
// we elide the text to the right so the text will be cut off with the three dots at the end.
@ -84,6 +91,19 @@ Button
border.color: button.enabled ? (button.hovered ? button.outlineHoverColor : button.outlineColor) : button.outlineDisabledColor
}
DropShadow
{
id: shadow
// Don't blur the shadow
radius: 0
anchors.fill: backgroundRect
source: backgroundRect
verticalOffset: 2
visible: false
// Should always be drawn behind the background.
z: backgroundRect.z - 1
}
ToolTip
{
id: tooltip
@ -91,12 +111,4 @@ Button
delay: 500
visible: text != "" && button.hovered
}
MouseArea
{
id: mouseArea
anchors.fill: parent
onPressed: mouse.accepted = false
hoverEnabled: true
}
}

View File

@ -12,7 +12,7 @@ Item
{
id: widget
Cura.ActionButton
Cura.PrimaryButton
{
id: saveToButton
height: parent.height
@ -42,6 +42,9 @@ Item
id: deviceSelectionMenu
height: parent.height
shadowEnabled: true
shadowColor: UM.Theme.getColor("primary_shadow")
anchors
{
top: parent.top
@ -65,7 +68,7 @@ Item
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
contentItem: Column
contentItem: ColumnLayout
{
Repeater
{
@ -77,7 +80,7 @@ Item
color: "transparent"
cornerRadius: 0
hoverColor: UM.Theme.getColor("primary")
Layout.fillWidth: true
onClicked:
{
UM.OutputDeviceManager.setActiveDevice(model.id)
@ -91,10 +94,7 @@ Item
{
opacity: visible ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100 } }
radius: UM.Theme.getSize("default_radius").width
color: UM.Theme.getColor("action_panel_secondary")
border.color: UM.Theme.getColor("lining")
border.width: UM.Theme.getSize("default_lining").width
}
}
}

View File

@ -18,6 +18,7 @@ Column
id: widget
spacing: UM.Theme.getSize("thin_margin").height
property bool preSlicedData: PrintInformation.preSliced
UM.I18nCatalog
{
@ -48,7 +49,7 @@ Column
id: estimatedTime
width: parent.width
text: PrintInformation.currentPrintTime.getDisplayString(UM.DurationFormat.Long)
text: preSlicedData ? catalog.i18nc("@label", "No time estimation available") : PrintInformation.currentPrintTime.getDisplayString(UM.DurationFormat.Long)
source: UM.Theme.getIcon("clock")
font: UM.Theme.getFont("small")
}
@ -63,6 +64,10 @@ Column
text:
{
if (preSlicedData)
{
return catalog.i18nc("@label", "No cost estimation available")
}
var totalLengths = 0
var totalWeights = 0
if (printMaterialLengths)
@ -86,6 +91,7 @@ Column
PrintInformationWidget
{
id: printInformationPanel
visible: !preSlicedData
anchors
{
@ -101,20 +107,18 @@ Column
spacing: UM.Theme.getSize("default_margin").width
width: parent.width
Cura.ActionButton
Cura.SecondaryButton
{
id: previewStageShortcut
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("action_panel_button").height
text: catalog.i18nc("@button", "Preview")
color: UM.Theme.getColor("secondary")
hoverColor: UM.Theme.getColor("secondary")
textColor: UM.Theme.getColor("primary")
textHoverColor: UM.Theme.getColor("text")
onClicked: UM.Controller.setActiveStage("PreviewStage")
visible: UM.Controller.activeStage != null && UM.Controller.activeStage.stageId != "PreviewStage"
shadowEnabled: true
shadowColor: UM.Theme.getColor("action_button_disabled_shadow")
}
Cura.OutputDevicesActionButton

View File

@ -40,9 +40,21 @@ Column
}
}
Label
{
id: autoSlicingLabel
width: parent.width
visible: prepareButtons.autoSlice && widget.backendState == UM.Backend.Processing
text: catalog.i18nc("@label:PrintjobStatus", "Auto slicing...")
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("very_small")
renderType: Text.NativeRendering
}
Cura.IconLabel
{
id: message
id: unableToSliceMessage
width: parent.width
visible: widget.backendState == UM.Backend.Error
@ -81,38 +93,41 @@ Column
}
}
Cura.ActionButton
{
id: prepareButton
width: parent.width
height: UM.Theme.getSize("action_panel_button").height
fixedWidthMode: true
text:
{
if ([UM.Backend.NotStarted, UM.Backend.Error].indexOf(widget.backendState) != -1)
{
return catalog.i18nc("@button", "Slice")
}
if (autoSlice)
{
return catalog.i18nc("@button", "Auto slicing...")
}
return catalog.i18nc("@button", "Cancel")
}
enabled: !autoSlice && !disabledSlice
Item
{
id: prepareButtons
// Get the current value from the preferences
property bool autoSlice: UM.Preferences.getValue("general/auto_slice")
// Disable the slice process when
property bool disabledSlice: [UM.Backend.Done, UM.Backend.Error].indexOf(widget.backendState) != -1
disabledColor: disabledSlice ? UM.Theme.getColor("action_button_disabled") : "transparent"
textDisabledColor: disabledSlice ? UM.Theme.getColor("action_button_disabled_text") : UM.Theme.getColor("primary")
outlineDisabledColor: disabledSlice ? UM.Theme.getColor("action_button_disabled_border") : "transparent"
width: parent.width
height: UM.Theme.getSize("action_panel_button").height
visible: !autoSlice
Cura.PrimaryButton
{
id: sliceButton
fixedWidthMode: true
anchors.fill: parent
text: catalog.i18nc("@button", "Slice")
enabled: widget.backendState != UM.Backend.Error
visible: widget.backendState == UM.Backend.NotStarted || widget.backendState == UM.Backend.Error
onClicked: sliceOrStopSlicing()
}
onClicked: sliceOrStopSlicing()
Cura.SecondaryButton
{
id: cancelButton
fixedWidthMode: true
anchors.fill: parent
text: catalog.i18nc("@button", "Cancel")
enabled: sliceButton.enabled
visible: !sliceButton.visible
onClicked: sliceOrStopSlicing()
}
}
// React when the user changes the preference of having the auto slice enabled
Connections
{
@ -120,7 +135,7 @@ Column
onPreferenceChanged:
{
var autoSlice = UM.Preferences.getValue("general/auto_slice")
prepareButton.autoSlice = autoSlice
prepareButtons.autoSlice = autoSlice
}
}

View File

@ -0,0 +1,10 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.0
QtObject
{
property real width: 0
property color color: "black"
}

View File

@ -6,6 +6,7 @@ import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
import QtGraphicalEffects 1.0
import UM 1.3 as UM
import Cura 1.1 as Cura
@ -153,7 +154,31 @@ UM.MainWindow
}
visible: stageMenu.source != ""
height: Math.round(UM.Theme.getSize("stage_menu").height / 2)
color: UM.Theme.getColor("main_window_header_background")
LinearGradient
{
anchors.fill: parent
start: Qt.point(0, 0)
end: Qt.point(parent.width, 0)
gradient: Gradient
{
GradientStop
{
position: 0.0
color: UM.Theme.getColor("main_window_header_background")
}
GradientStop
{
position: 0.5
color: UM.Theme.getColor("main_window_header_background_gradient")
}
GradientStop
{
position: 1.0
color: UM.Theme.getColor("main_window_header_background")
}
}
}
}
Connections
@ -187,7 +212,7 @@ UM.MainWindow
verticalCenter: parent.verticalCenter
left: parent.left
}
visible: CuraApplication.platformActivity
visible: CuraApplication.platformActivity && !PrintInformation.preSliced
}
ObjectsList

View File

@ -298,7 +298,6 @@ UM.Dialog
id: machineName
text: getMachineName()
width: Math.floor(parent.width * 0.75)
implicitWidth: UM.Theme.getSize("standard_list_input").width
maximumLength: 40
//validator: Cura.MachineNameValidator { } //TODO: Gives a segfault in PyQt5.6. For now, we must use a signal on text changed.
validator: RegExpValidator

View File

@ -2,6 +2,9 @@ import QtQuick 2.7
import QtQuick.Controls 2.3
import UM 1.2 as UM
import Cura 1.0 as Cura
import QtGraphicalEffects 1.0 // For the dropshadow
// The expandable component has 3 major sub components:
// * The headerItem; Always visible and should hold some info about what happens if the component is expanded
@ -10,6 +13,14 @@ import UM 1.2 as UM
Item
{
id: base
// Enumeration with the different possible alignments of the popup with respect of the headerItem
enum PopupAlignment
{
AlignLeft,
AlignRight
}
// The headerItem holds the QML item that is always displayed.
property alias headerItem: headerItemLoader.sourceComponent
@ -21,6 +32,9 @@ Item
property color headerBackgroundColor: UM.Theme.getColor("action_button")
property color headerHoverColor: UM.Theme.getColor("action_button_hovered")
// Defines the alignment of the popup with respect of the headerItem, by default to the right
property int popupAlignment: ExpandableComponent.PopupAlignment.AlignRight
// How much spacing is needed around the popupItem
property alias popupPadding: popup.padding
@ -52,6 +66,12 @@ Item
// Change the popupItem close behaviour
property alias popupClosePolicy : popup.closePolicy
property alias headerShadowColor: shadow.color
property alias enableHeaderShadow: shadow.visible
property int shadowOffset: 2
function togglePopup()
{
if(popup.visible)
@ -129,8 +149,8 @@ Item
sourceSize.height: height
visible: source != ""
width: height
height: 0.2 * base.height
color: "black"
height: Math.round(0.2 * base.height)
color: UM.Theme.getColor("text")
}
MouseArea
@ -143,23 +163,40 @@ Item
onExited: background.color = headerBackgroundColor
}
}
DropShadow
{
id: shadow
// Don't blur the shadow
radius: 0
anchors.fill: background
source: background
verticalOffset: base.shadowOffset
visible: true
color: UM.Theme.getColor("action_button_shadow")
// Should always be drawn behind the background.
z: background.z - 1
}
Popup
{
id: popup
// Ensure that the popup is located directly below the headerItem
y: headerItemLoader.height + 2 * background.padding + popupSpacingY
y: headerItemLoader.height + 2 * background.padding + base.shadowOffset + popupSpacingY
// Make the popup right aligned with the rest. The 3x padding is due to left, right and padding between
// the button & text.
x: -width + collapseButton.width + headerItemLoader.width + 3 * background.padding
// Make the popup aligned with the rest, using the property popupAlignment to decide whether is right or left.
// In case of right alignment, the 3x padding is due to left, right and padding between the button & text.
x: popupAlignment == ExpandableComponent.PopupAlignment.AlignRight ? -width + collapseButton.width + headerItemLoader.width + 3 * background.padding : 0
padding: UM.Theme.getSize("default_margin").width
closePolicy: Popup.CloseOnPressOutsideParent
background: Rectangle
background: Cura.RoundedRectangle
{
cornerSide: Cura.RoundedRectangle.Direction.Down
color: popupBackgroundColor
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
radius: UM.Theme.getSize("default_radius").width
}
}
}

View File

@ -7,7 +7,7 @@ import QtQuick.Controls 2.0
import UM 1.2 as UM
import Cura 1.0 as Cura
Button
Cura.ToolbarButton
{
id: base
@ -18,11 +18,9 @@ Button
checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1
enabled: UM.Selection.hasSelection && extruder.stack.isEnabled
background: Item {}
contentItem: ExtruderIcon
toolItem: ExtruderIcon
{
width: UM.Theme.getSize("button_icon").width
materialColor: model.color
materialColor: extruder.color
extruderEnabled: extruder.stack.isEnabled
property int index: extruder.index
}
@ -30,6 +28,6 @@ Button
onClicked:
{
forceActiveFocus() //First grab focus, so all the text fields are updated
CuraActions.setExtruderForSelection(extruder.id);
CuraActions.setExtruderForSelection(extruder.id)
}
}

View File

@ -16,6 +16,7 @@ Item
property color materialColor
property alias textColor: extruderNumberText.color
property bool extruderEnabled: true
UM.RecolorImage
{
id: mainIcon
@ -50,8 +51,6 @@ Item
anchors.centerIn: parent
text: index + 1
font: UM.Theme.getFont("extruder_icon")
width: contentWidth
height: contentHeight
visible: extruderEnabled
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignHCenter

View File

@ -16,32 +16,37 @@ Item
property alias source: icon.source
property alias color: label.color
property alias font: label.font
property alias iconSize: icon.width
height: childrenRect.height
implicitHeight: icon.height
UM.RecolorImage
{
id: icon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
source: UM.Theme.getIcon("dot")
source: ""
width: UM.Theme.getSize("section_icon").width
height: UM.Theme.getSize("section_icon").height
height: width
sourceSize.width: width
sourceSize.height: height
color: label.color
visible: source != ""
}
Label
{
id: label
anchors.left: icon.right
anchors.left: icon.visible ? icon.right : parent.left
anchors.right: parent.right
anchors.leftMargin: UM.Theme.getSize("thin_margin").width
anchors.verticalCenter: icon.verticalCenter
text: "Empty label"
elide: Text.ElideRight
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("very_small")
renderType: Text.NativeRendering

View File

@ -1,140 +0,0 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 2.3
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
import "Menus"
Cura.ExpandableComponent
{
id: machineSelector
property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != ""
iconSource: expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left")
UM.I18nCatalog
{
id: catalog
name: "cura"
}
headerItem: Label
{
text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName
verticalAlignment: Text.AlignVCenter
height: parent.height
elide: Text.ElideRight
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
}
popupItem: Item
{
id: popup
width: machineSelector.width - 2 * UM.Theme.getSize("default_margin").width
height: 200
ScrollView
{
anchors.fill: parent
contentHeight: column.implicitHeight
contentWidth: column.implicitWidth
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
Column
{
id: column
anchors.fill: parent
Label
{
text: catalog.i18nc("@label", "Networked Printers")
visible: networkedPrintersModel.items.length > 0
height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0
font: UM.Theme.getFont("medium_bold")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
}
Repeater
{
id: networkedPrinters
model: UM.ContainerStacksModel
{
id: networkedPrintersModel
filter: {"type": "machine", "um_network_key": "*", "hidden": "False"}
}
delegate: RoundButton
{
text: name
width: parent.width
checkable: true
radius: UM.Theme.getSize("default_radius").width
onClicked:
{
togglePopup()
Cura.MachineManager.setActiveMachine(model.id)
}
Connections
{
target: Cura.MachineManager
onActiveMachineNetworkGroupNameChanged: checked = Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
}
}
}
Label
{
text: catalog.i18nc("@label", "Virtual Printers")
visible: virtualPrintersModel.items.length > 0
height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0
font: UM.Theme.getFont("medium_bold")
color: UM.Theme.getColor("text")
verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering
}
Repeater
{
id: virtualPrinters
model: UM.ContainerStacksModel
{
id: virtualPrintersModel
filter: {"type": "machine", "um_network_key": null}
}
delegate: RoundButton
{
text: name
width: parent.width
checked: Cura.MachineManager.activeMachineId == model.id
checkable: true
radius: UM.Theme.getSize("default_radius").width
onClicked:
{
togglePopup()
Cura.MachineManager.setActiveMachine(model.id)
}
}
}
}
}
}
}

View File

@ -2,11 +2,13 @@
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.0 as Controls2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.1
import UM 1.4 as UM
import Cura 1.0 as Cura
import QtGraphicalEffects 1.0
import "../Account"
@ -16,7 +18,31 @@ Rectangle
implicitHeight: UM.Theme.getSize("main_window_header").height
implicitWidth: UM.Theme.getSize("main_window_header").width
color: UM.Theme.getColor("main_window_header_background")
LinearGradient
{
anchors.fill: parent
start: Qt.point(0, 0)
end: Qt.point(parent.width, 0)
gradient: Gradient
{
GradientStop
{
position: 0.0
color: UM.Theme.getColor("main_window_header_background")
}
GradientStop
{
position: 0.5
color: UM.Theme.getColor("main_window_header_background_gradient")
}
GradientStop
{
position: 1.0
color: UM.Theme.getColor("main_window_header_background")
}
}
}
Image
{
@ -73,25 +99,39 @@ Rectangle
}
// Shortcut button to quick access the Toolbox
Cura.ActionButton
Controls2.Button
{
id: marketplaceButton
text: catalog.i18nc("@action:button", "Marketplace")
height: Math.round(0.5 * UM.Theme.getSize("main_window_header").height)
onClicked: Cura.Actions.browsePackages.trigger()
hoverEnabled: true
background: Rectangle
{
radius: UM.Theme.getSize("action_button_radius").width
color: marketplaceButton.hovered ? UM.Theme.getColor("primary_text") : UM.Theme.getColor("main_window_header_background")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("primary_text")
}
contentItem: Label
{
id: label
text: marketplaceButton.text
color: marketplaceButton.hovered ? UM.Theme.getColor("main_window_header_background") : UM.Theme.getColor("primary_text")
width: contentWidth
verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering
}
anchors
{
right: accountWidget.left
rightMargin: UM.Theme.getSize("default_margin").width
verticalCenter: parent.verticalCenter
}
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@action:button", "Marketplace")
height: Math.round(0.5 * UM.Theme.getSize("main_window_header").height)
color: UM.Theme.getColor("main_window_header_secondary_button_background_active")
hoverColor: UM.Theme.getColor("main_window_header_secondary_button_background_hovered")
outlineColor: UM.Theme.getColor("main_window_header_secondary_button_outline_active")
outlineHoverColor: UM.Theme.getColor("main_window_header_secondary_button_outline_hovered")
textColor: UM.Theme.getColor("main_window_header_secondary_button_text_active")
textHoverColor: UM.Theme.getColor("main_window_header_secondary_button_text_hovered")
onClicked: Cura.Actions.browsePackages.trigger()
}
AccountWidget

View File

@ -21,7 +21,7 @@ Column
{
// FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI
configurationList.model = []
if(outputDevice)
if (outputDevice)
{
configurationList.model = outputDevice.uniqueConfigurations
}

View File

@ -1,27 +0,0 @@
// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import UM 1.2 as UM
import Cura 1.0 as Cura
Item
{
property var status: "disconnected"
width: childrenRect.width
height: childrenRect.height
UM.RecolorImage
{
id: statusIcon
width: UM.Theme.getSize("printer_status_icon").width
height: UM.Theme.getSize("printer_status_icon").height
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.getColor("tab_status_" + parent.status)
source: UM.Theme.getIcon(parent.status)
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) 2018 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("primary_button_shadow"): UM.Theme.getColor("action_button_disabled_shadow")
color: UM.Theme.getColor("primary_button")
textColor: UM.Theme.getColor("primary_button_text")
outlineColor: "transparent"
disabledColor: UM.Theme.getColor("action_button_disabled")
textDisabledColor: UM.Theme.getColor("action_button_disabled_text")
hoverColor: UM.Theme.getColor("primary_button_hover")
}

View File

@ -64,12 +64,12 @@ Cura.ExpandableComponent
IconWithText
{
source: UM.Theme.getIcon("category_layer_height")
text: Cura.MachineManager.activeQualityOrQualityChangesName + " " + layerHeight.properties.value + "mm"
text: Cura.MachineManager.activeStack ? Cura.MachineManager.activeQualityOrQualityChangesName + " " + layerHeight.properties.value + "mm" : ""
UM.SettingPropertyProvider
{
id: layerHeight
containerStackId: Cura.MachineManager.activeStackId
containerStack: Cura.MachineManager.activeStack
key: "layer_height"
watchedProperties: ["value"]
}
@ -78,12 +78,12 @@ Cura.ExpandableComponent
IconWithText
{
source: UM.Theme.getIcon("category_infill")
text: parseInt(infillDensity.properties.value) + "%"
text: Cura.MachineManager.activeStack ? parseInt(infillDensity.properties.value) + "%" : "0%"
UM.SettingPropertyProvider
{
id: infillDensity
containerStackId: Cura.MachineManager.activeStackId
containerStack: Cura.MachineManager.activeStack
key: "infill_sparse_density"
watchedProperties: ["value"]
}

View File

@ -0,0 +1,155 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.3
import UM 1.2 as UM
import Cura 1.0 as Cura
Cura.ExpandableComponent
{
id: machineSelector
property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != ""
property bool isPrinterConnected: Cura.MachineManager.printerConnected
property var outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
popupPadding: UM.Theme.getSize("default_lining").width
popupAlignment: Cura.ExpandableComponent.PopupAlignment.AlignLeft
iconSource: expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left")
UM.I18nCatalog
{
id: catalog
name: "cura"
}
headerItem: Cura.IconLabel
{
text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName
source:
{
if (isNetworkPrinter)
{
if (machineSelector.outputDevice != null && machineSelector.outputDevice.clusterSize > 1)
{
return UM.Theme.getIcon("printer_group")
}
return UM.Theme.getIcon("printer_single")
}
return ""
}
font: UM.Theme.getFont("medium")
color: UM.Theme.getColor("text")
iconSize: UM.Theme.getSize("machine_selector_icon").width
UM.RecolorImage
{
id: icon
anchors
{
bottom: parent.bottom
left: parent.left
leftMargin: UM.Theme.getSize("thick_margin").width
}
source: UM.Theme.getIcon("printer_connected")
width: UM.Theme.getSize("printer_status_icon").width
height: UM.Theme.getSize("printer_status_icon").height
sourceSize.width: width
sourceSize.height: height
color: UM.Theme.getColor("primary")
visible: isNetworkPrinter && isPrinterConnected
// Make a themable circle in the background so we can change it in other themes
Rectangle
{
id: iconBackground
anchors.centerIn: parent
// Make it a bit bigger so there is an outline
width: parent.width + 2 * UM.Theme.getSize("default_lining").width
height: parent.height + 2 * UM.Theme.getSize("default_lining").height
radius: Math.round(width / 2)
color: UM.Theme.getColor("main_background")
z: parent.z - 1
}
}
}
popupItem: Item
{
id: popup
width: UM.Theme.getSize("machine_selector_widget_content").width
ScrollView
{
id: scroll
width: parent.width
clip: true
leftPadding: UM.Theme.getSize("default_lining").width
rightPadding: UM.Theme.getSize("default_lining").width
MachineSelectorList
{
// Can't use parent.width since the parent is the flickable component and not the ScrollView
width: scroll.width - scroll.leftPadding - scroll.rightPadding
property real maximumHeight: UM.Theme.getSize("machine_selector_widget_content").height - buttonRow.height
onHeightChanged:
{
scroll.height = Math.min(height, maximumHeight)
popup.height = scroll.height + buttonRow.height
}
}
}
Rectangle
{
id: separator
anchors.top: scroll.bottom
width: parent.width
height: UM.Theme.getSize("default_lining").height
color: UM.Theme.getColor("lining")
}
Row
{
id: buttonRow
// The separator is inside the buttonRow. This is to avoid some weird behaviours with the scroll bar.
anchors.top: separator.top
anchors.horizontalCenter: parent.horizontalCenter
padding: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").width
Cura.SecondaryButton
{
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@button", "Add printer")
onClicked:
{
togglePopup()
Cura.Actions.addMachine.trigger()
}
}
Cura.SecondaryButton
{
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@button", "Manage printers")
onClicked:
{
togglePopup()
Cura.Actions.configureMachines.trigger()
}
}
}
}
}

View File

@ -0,0 +1,103 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import UM 1.1 as UM
import Cura 1.0 as Cura
Button
{
id: machineSelectorButton
width: parent.width
height: UM.Theme.getSize("action_button").height
leftPadding: UM.Theme.getSize("thick_margin").width
rightPadding: UM.Theme.getSize("thick_margin").width
checkable: true
hoverEnabled: true
property var outputDevice: null
property var printerTypesList: []
function updatePrinterTypesList()
{
printerTypesList = (checked && (outputDevice != null)) ? outputDevice.uniquePrinterTypes : []
}
contentItem: Item
{
width: machineSelectorButton.width - machineSelectorButton.leftPadding
height: UM.Theme.getSize("action_button").height
Label
{
id: buttonText
anchors
{
left: parent.left
right: printerTypes.left
verticalCenter: parent.verticalCenter
}
text: machineSelectorButton.text
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("action_button")
visible: text != ""
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
Row
{
id: printerTypes
width: childrenRect.width
anchors
{
right: parent.right
verticalCenter: parent.verticalCenter
}
spacing: UM.Theme.getSize("narrow_margin").width
Repeater
{
model: printerTypesList
delegate: Cura.PrinterTypeLabel
{
text: Cura.MachineManager.getAbbreviatedMachineName(modelData)
}
}
}
}
background: Rectangle
{
id: backgroundRect
color: machineSelectorButton.hovered ? UM.Theme.getColor("action_button_hovered") : "transparent"
radius: UM.Theme.getSize("action_button_radius").width
border.width: UM.Theme.getSize("default_lining").width
border.color: machineSelectorButton.checked ? UM.Theme.getColor("primary") : "transparent"
}
onClicked:
{
togglePopup()
Cura.MachineManager.setActiveMachine(model.id)
}
Connections
{
target: outputDevice
onUniqueConfigurationsChanged: updatePrinterTypesList()
}
Connections
{
target: Cura.MachineManager
onOutputDevicesChanged: updatePrinterTypesList()
}
Component.onCompleted: updatePrinterTypesList()
}

View File

@ -0,0 +1,84 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.3
import UM 1.2 as UM
import Cura 1.0 as Cura
Column
{
id: machineSelectorList
Label
{
text: catalog.i18nc("@label", "Network connected printers")
visible: networkedPrintersModel.items.length > 0
leftPadding: UM.Theme.getSize("default_margin").width
height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0
renderType: Text.NativeRendering
font: UM.Theme.getFont("medium")
color: UM.Theme.getColor("text_medium")
verticalAlignment: Text.AlignVCenter
}
Repeater
{
id: networkedPrinters
model: UM.ContainerStacksModel
{
id: networkedPrintersModel
filter:
{
"type": "machine", "um_network_key": "*", "hidden": "False"
}
}
delegate: MachineSelectorButton
{
text: model.metadata["connect_group_name"]
checked: Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
Connections
{
target: Cura.MachineManager
onActiveMachineNetworkGroupNameChanged: checked = Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
}
}
}
Label
{
text: catalog.i18nc("@label", "Preset printers")
visible: virtualPrintersModel.items.length > 0
leftPadding: UM.Theme.getSize("default_margin").width
height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0
renderType: Text.NativeRendering
font: UM.Theme.getFont("medium")
color: UM.Theme.getColor("text_medium")
verticalAlignment: Text.AlignVCenter
}
Repeater
{
id: virtualPrinters
model: UM.ContainerStacksModel
{
id: virtualPrintersModel
filter:
{
"type": "machine", "um_network_key": null
}
}
delegate: MachineSelectorButton
{
text: model.name
checked: Cura.MachineManager.activeMachineId == model.id
}
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import UM 1.1 as UM
// This component creates a label with the abbreviated name of a printer, with a rectangle surrounding the label.
// It is created in a separated place in order to be reused whenever needed.
Item
{
property alias text: printerTypeLabel.text
width: UM.Theme.getSize("printer_type_label").width
height: UM.Theme.getSize("printer_type_label").height
Rectangle
{
anchors.fill: parent
color: UM.Theme.getColor("printer_type_label_background")
}
Label
{
id: printerTypeLabel
text: "CFFFP" // As an abbreviated name of the Custom FFF Printer
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
renderType: Text.NativeRendering
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text")
}
}

View File

@ -5,6 +5,7 @@ import UM 1.2 as UM
// The rounded rectangle works mostly like a regular rectangle, but provides the option to have rounded corners on only one side of the rectangle.
Item
{
id: roundedRectangle
// As per the regular rectangle
property color color: "transparent"
@ -15,6 +16,9 @@ Item
// 1 is down, 2 is left, 3 is up and 4 is right.
property int cornerSide: RoundedRectangle.Direction.None
// Simple object to ensure that border.width and border.color work
property BorderGroup border: BorderGroup {}
enum Direction
{
None = 0,
@ -31,6 +35,8 @@ Item
anchors.fill: parent
radius: cornerSide != RoundedRectangle.Direction.None ? parent.radius : 0
color: parent.color
border.width: parent.border.width
border.color: parent.border.color
}
// The item that covers 2 of the corners to make them not rounded.
@ -45,5 +51,22 @@ Item
right: cornerSide == RoundedRectangle.Direction.Left ? parent.right: undefined
bottom: cornerSide == RoundedRectangle.Direction.Up ? parent.bottom: undefined
}
border.width: parent.border.width
border.color: parent.border.color
Rectangle
{
color: roundedRectangle.color
height: cornerSide % 2 ? roundedRectangle.border.width: roundedRectangle.height - 2 * roundedRectangle.border.width
width: cornerSide % 2 ? roundedRectangle.width - 2 * roundedRectangle.border.width: roundedRectangle.border.width
anchors
{
right: cornerSide == RoundedRectangle.Direction.Right ? parent.right : undefined
bottom: cornerSide == RoundedRectangle.Direction.Down ? parent.bottom: undefined
horizontalCenter: cornerSide % 2 ? parent.horizontalCenter: undefined
verticalCenter: cornerSide % 2 ? undefined: parent.verticalCenter
}
}
}
}

View File

@ -1,478 +0,0 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.1 as UM
import Cura 1.0 as Cura
// This widget does so much more than "just" being a save button, so it should be refactored at some point in time.
Item
{
id: base;
UM.I18nCatalog { id: catalog; name: "cura"}
property real progress: UM.Backend.progress
property int backendState: UM.Backend.state
property bool activity: CuraApplication.platformActivity
property alias buttonRowWidth: saveRow.width
property string fileBaseName
property string statusText:
{
if(!activity)
{
return catalog.i18nc("@label:PrintjobStatus", "Please load a 3D model");
}
switch(base.backendState)
{
case 1:
return catalog.i18nc("@label:PrintjobStatus", "Ready to slice");
case 2:
return catalog.i18nc("@label:PrintjobStatus", "Slicing...");
case 3:
return catalog.i18nc("@label:PrintjobStatus %1 is target operation", "Ready to %1").arg(UM.OutputDeviceManager.activeDeviceShortDescription);
case 4:
return catalog.i18nc("@label:PrintjobStatus", "Unable to Slice");
case 5:
return catalog.i18nc("@label:PrintjobStatus", "Slicing unavailable");
default:
return "";
}
}
function sliceOrStopSlicing()
{
try
{
if ([1, 5].indexOf(base.backendState) != -1)
{
CuraApplication.backend.forceSlice();
}
else
{
CuraApplication.backend.stopSlicing();
}
}
catch (e)
{
console.log("Could not start or stop slicing.", e)
}
}
Label
{
id: statusLabel
width: parent.width - 2 * UM.Theme.getSize("thick_margin").width
anchors.top: parent.top
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("thick_margin").width
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("default_bold")
text: statusText;
}
Rectangle
{
id: progressBar
width: parent.width - 2 * UM.Theme.getSize("thick_margin").width
height: UM.Theme.getSize("progressbar").height
anchors.top: statusLabel.bottom
anchors.topMargin: Math.round(UM.Theme.getSize("thick_margin").height / 4)
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("thick_margin").width
radius: UM.Theme.getSize("progressbar_radius").width
color: UM.Theme.getColor("progressbar_background")
Rectangle
{
width: Math.max(parent.width * base.progress)
height: parent.height
color: UM.Theme.getColor("progressbar_control")
radius: UM.Theme.getSize("progressbar_radius").width
visible: base.backendState == 2
}
}
// Shortcut for "save as/print/..."
Action
{
shortcut: "Ctrl+P"
onTriggered:
{
// only work when the button is enabled
if (saveToButton.enabled)
{
saveToButton.clicked();
}
// prepare button
if (prepareButton.enabled)
{
sliceOrStopSlicing();
}
}
}
Item
{
id: saveRow
width: {
// using childrenRect.width directly causes a binding loop, because setting the width affects the childrenRect
var children_width = UM.Theme.getSize("default_margin").width;
for (var index in children)
{
var child = children[index];
if(child.visible)
{
children_width += child.width + child.anchors.rightMargin;
}
}
return Math.min(children_width, base.width - UM.Theme.getSize("thick_margin").width);
}
height: saveToButton.height
anchors.bottom: parent.bottom
anchors.bottomMargin: UM.Theme.getSize("thick_margin").height
anchors.right: parent.right
clip: true
Row
{
id: additionalComponentsRow
anchors.top: parent.top
anchors.right: saveToButton.visible ? saveToButton.left : (prepareButton.visible ? prepareButton.left : parent.right)
anchors.rightMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").width
}
Component.onCompleted:
{
saveRow.addAdditionalComponents("saveButton")
}
Connections
{
target: CuraApplication
onAdditionalComponentsChanged: saveRow.addAdditionalComponents("saveButton")
}
function addAdditionalComponents (areaId)
{
if(areaId == "saveButton")
{
for (var component in CuraApplication.additionalComponents["saveButton"])
{
CuraApplication.additionalComponents["saveButton"][component].parent = additionalComponentsRow
}
}
}
Connections
{
target: UM.Preferences
onPreferenceChanged:
{
var autoSlice = UM.Preferences.getValue("general/auto_slice");
prepareButton.autoSlice = autoSlice;
saveToButton.autoSlice = autoSlice;
}
}
// Prepare button, only shows if auto_slice is off
Button
{
id: prepareButton
tooltip: [1, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@info:tooltip","Slice current printjob") : catalog.i18nc("@info:tooltip","Cancel slicing process")
// 1 = not started, 2 = Processing
enabled: ([1, 2].indexOf(base.backendState) != -1) && base.activity
visible: !autoSlice && ([1, 2, 4].indexOf(base.backendState) != -1) && base.activity
property bool autoSlice
height: UM.Theme.getSize("save_button_save_to_button").height
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("thick_margin").width
// 1 = not started, 4 = error, 5 = disabled
text: [1, 4, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@label:Printjob", "Prepare") : catalog.i18nc("@label:Printjob", "Cancel")
onClicked:
{
sliceOrStopSlicing();
}
style: ButtonStyle
{
background: Rectangle
{
border.width: UM.Theme.getSize("default_lining").width
border.color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_border");
}
else if(control.pressed)
{
return UM.Theme.getColor("action_button_active_border");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered_border");
}
else
{
return UM.Theme.getColor("action_button_border");
}
}
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled");
}
else if(control.pressed)
{
return UM.Theme.getColor("action_button_active");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered");
}
else
{
return UM.Theme.getColor("action_button");
}
}
Behavior on color { ColorAnimation { duration: 50; } }
implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("thick_margin").width * 2)
Label
{
id: actualLabel
anchors.centerIn: parent
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_text");
}
else if(control.pressed)
{
return UM.Theme.getColor("action_button_active_text");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered_text");
}
else
{
return UM.Theme.getColor("action_button_text");
}
}
font: UM.Theme.getFont("action_button")
text: control.text;
}
}
label: Item {}
}
}
Button
{
id: saveToButton
tooltip: UM.OutputDeviceManager.activeDeviceDescription;
// 3 = done, 5 = disabled
enabled: base.backendState != "undefined" && (base.backendState == 3 || base.backendState == 5) && base.activity == true
visible: base.backendState != "undefined" && autoSlice || ((base.backendState == 3 || base.backendState == 5) && base.activity == true)
property bool autoSlice
height: UM.Theme.getSize("save_button_save_to_button").height
anchors.top: parent.top
anchors.right: deviceSelectionMenu.visible ? deviceSelectionMenu.left : parent.right
anchors.rightMargin: deviceSelectionMenu.visible ? -3 * UM.Theme.getSize("default_lining").width : UM.Theme.getSize("thick_margin").width
text: UM.OutputDeviceManager.activeDeviceShortDescription
onClicked:
{
forceActiveFocus();
UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName,
{ "filter_by_machine": true, "preferred_mimetypes": Cura.MachineManager.activeMachine.preferred_output_file_formats });
}
style: ButtonStyle
{
background: Rectangle
{
border.width: UM.Theme.getSize("default_lining").width
border.color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_border");
}
else if(control.pressed)
{
return UM.Theme.getColor("print_button_ready_pressed_border");
}
else if(control.hovered)
{
return UM.Theme.getColor("print_button_ready_hovered_border");
}
else
{
return UM.Theme.getColor("print_button_ready_border");
}
}
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled");
}
else if(control.pressed)
{
return UM.Theme.getColor("print_button_ready_pressed");
}
else if(control.hovered)
{
return UM.Theme.getColor("print_button_ready_hovered");
}
else
{
return UM.Theme.getColor("print_button_ready");
}
}
Behavior on color { ColorAnimation { duration: 50; } }
implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("thick_margin").width * 2)
Label
{
id: actualLabel
anchors.centerIn: parent
color: control.enabled ? UM.Theme.getColor("print_button_ready_text") : UM.Theme.getColor("action_button_disabled_text")
font: UM.Theme.getFont("action_button")
text: control.text
}
}
label: Item { }
}
}
Button
{
id: deviceSelectionMenu
tooltip: catalog.i18nc("@info:tooltip","Select the active output device");
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("thick_margin").width
width: UM.Theme.getSize("save_button_save_to_button").height
height: UM.Theme.getSize("save_button_save_to_button").height
// 3 = Done, 5 = Disabled
enabled: (base.backendState == 3 || base.backendState == 5) && base.activity == true
visible: (devicesModel.deviceCount > 1) && (base.backendState == 3 || base.backendState == 5) && base.activity == true
style: ButtonStyle
{
background: Rectangle
{
id: deviceSelectionIcon
border.width: UM.Theme.getSize("default_lining").width
border.color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_border")
}
else if(control.pressed)
{
return UM.Theme.getColor("print_button_ready_pressed_border")
}
else if(control.hovered)
{
return UM.Theme.getColor("print_button_ready_hovered_border")
}
else
{
return UM.Theme.getColor("print_button_ready_border")
}
}
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled")
}
else if(control.pressed)
{
return UM.Theme.getColor("print_button_ready_pressed")
}
else if(control.hovered)
{
return UM.Theme.getColor("print_button_ready_hovered")
}
else
{
return UM.Theme.getColor("print_button_ready")
}
}
Behavior on color { ColorAnimation { duration: 50; } }
anchors.left: parent.left
anchors.leftMargin: Math.round(UM.Theme.getSize("save_button_text_margin").width / 2);
width: parent.height
height: parent.height
UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
sourceSize.width: width
sourceSize.height: height
color: control.enabled ? UM.Theme.getColor("print_button_ready_text") : UM.Theme.getColor("action_button_disabled_text")
source: UM.Theme.getIcon("arrow_bottom")
}
}
}
menu: Menu
{
id: devicesMenu;
Instantiator
{
model: devicesModel;
MenuItem
{
text: model.description
checkable: true;
checked: model.id == UM.OutputDeviceManager.activeDevice
exclusiveGroup: devicesMenuGroup
onTriggered:
{
UM.OutputDeviceManager.setActiveDevice(model.id);
}
}
onObjectAdded: devicesMenu.insertItem(index, object)
onObjectRemoved: devicesMenu.removeItem(object)
}
ExclusiveGroup { id: devicesMenuGroup }
}
}
UM.OutputDevicesModel { id: devicesModel }
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) 2018 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: UM.Theme.getColor("secondary_button")
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: UM.Theme.getColor("secondary_button_hover")
}

View File

@ -14,23 +14,32 @@ Button
anchors.right: parent.right
anchors.leftMargin: UM.Theme.getSize("thick_margin").width
anchors.rightMargin: UM.Theme.getSize("thick_margin").width
hoverEnabled: true
background: Rectangle
{
id: backgroundRectangle
implicitHeight: UM.Theme.getSize("section").height
color: {
if (base.color) {
return base.color;
} else if (!base.enabled) {
return UM.Theme.getColor("setting_category_disabled");
} else if (base.hovered && base.checkable && base.checked) {
return UM.Theme.getColor("setting_category_active_hover");
} else if (base.pressed || (base.checkable && base.checked)) {
return UM.Theme.getColor("setting_category_active");
} else if (base.hovered) {
return UM.Theme.getColor("setting_category_hover");
} else {
return UM.Theme.getColor("setting_category");
color:
{
if (base.color)
{
return base.color
} else if (!base.enabled)
{
return UM.Theme.getColor("setting_category_disabled")
} else if (base.hovered && base.checkable && base.checked)
{
return UM.Theme.getColor("setting_category_active_hover")
} else if (base.pressed || (base.checkable && base.checked))
{
return UM.Theme.getColor("setting_category_active")
} else if (base.hovered)
{
return UM.Theme.getColor("setting_category_hover")
} else
{
return UM.Theme.getColor("setting_category")
}
}
Behavior on color { ColorAnimation { duration: 50; } }
@ -40,17 +49,23 @@ Button
height: UM.Theme.getSize("default_lining").height
width: parent.width
anchors.bottom: parent.bottom
color: {
if (!base.enabled) {
return UM.Theme.getColor("setting_category_disabled_border");
} else if ((base.hovered || base.activeFocus) && base.checkable && base.checked) {
return UM.Theme.getColor("setting_category_active_hover_border");
} else if (base.pressed || (base.checkable && base.checked)) {
return UM.Theme.getColor("setting_category_active_border");
} else if (base.hovered || base.activeFocus) {
return UM.Theme.getColor("setting_category_hover_border");
} else {
return UM.Theme.getColor("setting_category_border");
color:
{
if (!base.enabled)
{
return UM.Theme.getColor("setting_category_disabled_border")
} else if ((base.hovered || base.activeFocus) && base.checkable && base.checked)
{
return UM.Theme.getColor("setting_category_active_hover_border")
} else if (base.pressed || (base.checkable && base.checked))
{
return UM.Theme.getColor("setting_category_active_border")
} else if (base.hovered || base.activeFocus)
{
return UM.Theme.getColor("setting_category_hover_border")
} else
{
return UM.Theme.getColor("setting_category_border")
}
}
}
@ -65,18 +80,19 @@ Button
property var focusItem: base
contentItem: Item {
contentItem: Item
{
anchors.fill: parent
anchors.left: parent.left
Label {
Label
{
id: settingNameLabel
anchors
{
left: parent.left
leftMargin: 2 * UM.Theme.getSize("default_margin").width + UM.Theme.getSize("section_icon").width
right: parent.right;
verticalCenter: parent.verticalCenter;
right: parent.right
verticalCenter: parent.verticalCenter
}
text: definition.label
textFormat: Text.PlainText
@ -84,21 +100,27 @@ Button
font: UM.Theme.getFont("setting_category")
color:
{
if (!base.enabled) {
return UM.Theme.getColor("setting_category_disabled_text");
} else if ((base.hovered || base.activeFocus) && base.checkable && base.checked) {
return UM.Theme.getColor("setting_category_active_hover_text");
} else if (base.pressed || (base.checkable && base.checked)) {
return UM.Theme.getColor("setting_category_active_text");
} else if (base.hovered || base.activeFocus) {
return UM.Theme.getColor("setting_category_hover_text");
} else {
return UM.Theme.getColor("setting_category_text");
if (!base.enabled)
{
return UM.Theme.getColor("setting_category_disabled_text")
} else if ((base.hovered || base.activeFocus) && base.checkable && base.checked)
{
return UM.Theme.getColor("setting_category_active_hover_text")
} else if (base.pressed || (base.checkable && base.checked))
{
return UM.Theme.getColor("setting_category_active_text")
} else if (base.hovered || base.activeFocus)
{
return UM.Theme.getColor("setting_category_hover_text")
} else
{
return UM.Theme.getColor("setting_category_text")
}
}
fontSizeMode: Text.HorizontalFit
minimumPointSize: 8
}
UM.RecolorImage
{
id: category_arrow
@ -111,16 +133,21 @@ Button
sourceSize.height: width
color:
{
if (!base.enabled) {
return UM.Theme.getColor("setting_category_disabled_text");
} else if ((base.hovered || base.activeFocus) && base.checkable && base.checked) {
return UM.Theme.getColor("setting_category_active_hover_text");
} else if (base.pressed || (base.checkable && base.checked)) {
return UM.Theme.getColor("setting_category_active_text");
} else if (base.hovered || base.activeFocus) {
return UM.Theme.getColor("setting_category_hover_text");
} else {
return UM.Theme.getColor("setting_category_text");
if (!base.enabled)
{
return UM.Theme.getColor("setting_category_disabled_text")
} else if ((base.hovered || base.activeFocus) && base.checkable && base.checked)
{
return UM.Theme.getColor("setting_category_active_hover_text")
} else if (base.pressed || (base.checkable && base.checked))
{
return UM.Theme.getColor("setting_category_active_text")
} else if (base.hovered || base.activeFocus)
{
return UM.Theme.getColor("setting_category_hover_text")
} else
{
return UM.Theme.getColor("setting_category_text")
}
}
source: base.checked ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left")
@ -135,21 +162,26 @@ Button
anchors.leftMargin: UM.Theme.getSize("default_margin").width
color:
{
if (!base.enabled) {
return UM.Theme.getColor("setting_category_disabled_text");
} else if((base.hovered || base.activeFocus) && base.checkable && base.checked) {
return UM.Theme.getColor("setting_category_active_hover_text");
} else if(base.pressed || (base.checkable && base.checked)) {
return UM.Theme.getColor("setting_category_active_text");
} else if(base.hovered || base.activeFocus) {
return UM.Theme.getColor("setting_category_hover_text");
} else {
return UM.Theme.getColor("setting_category_text");
if (!base.enabled)
{
return UM.Theme.getColor("setting_category_disabled_text")
} else if((base.hovered || base.activeFocus) && base.checkable && base.checked)
{
return UM.Theme.getColor("setting_category_active_hover_text")
} else if(base.pressed || (base.checkable && base.checked))
{
return UM.Theme.getColor("setting_category_active_text")
} else if(base.hovered || base.activeFocus)
{
return UM.Theme.getColor("setting_category_hover_text")
} else
{
return UM.Theme.getColor("setting_category_text")
}
}
source: UM.Theme.getIcon(definition.icon)
width: UM.Theme.getSize("section_icon").width;
height: UM.Theme.getSize("section_icon").height;
width: UM.Theme.getSize("section_icon").width
height: UM.Theme.getSize("section_icon").height
sourceSize.width: width + 15 * screenScaleFactor
sourceSize.height: width + 15 * screenScaleFactor
}
@ -159,31 +191,26 @@ Button
onClicked:
{
if (definition.expanded) {
settingDefinitionsModel.collapse(definition.key);
if (definition.expanded)
{
settingDefinitionsModel.collapse(definition.key)
} else {
settingDefinitionsModel.expandRecursive(definition.key);
settingDefinitionsModel.expandRecursive(definition.key)
}
//Set focus so that tab navigation continues from this point on.
//NB: This must be set AFTER collapsing/expanding the category so that the scroll position is correct.
forceActiveFocus();
forceActiveFocus()
}
onActiveFocusChanged:
{
if(activeFocus)
{
base.focusReceived();
base.focusReceived()
}
}
Keys.onTabPressed:
{
base.setActiveFocusToNextSetting(true)
}
Keys.onBacktabPressed:
{
base.setActiveFocusToNextSetting(false)
}
Keys.onTabPressed: base.setActiveFocusToNextSetting(true)
Keys.onBacktabPressed: base.setActiveFocusToNextSetting(false)
UM.SimpleButton
{
@ -193,9 +220,10 @@ Button
height: Math.round(base.height * 0.6)
width: Math.round(base.height * 0.6)
anchors {
anchors
{
right: inheritButton.visible ? inheritButton.left : parent.right
// use 1.9 as the factor because there is a 0.1 difference between the settings and inheritance warning icons
// Use 1.9 as the factor because there is a 0.1 difference between the settings and inheritance warning icons
rightMargin: inheritButton.visible ? Math.round(UM.Theme.getSize("default_margin").width / 2) : category_arrow.width + Math.round(UM.Theme.getSize("default_margin").width * 1.9)
verticalCenter: parent.verticalCenter
}
@ -204,9 +232,7 @@ Button
hoverColor: UM.Theme.getColor("setting_control_button_hover")
iconSource: UM.Theme.getIcon("settings")
onClicked: {
Cura.Actions.configureSettingVisibility.trigger(definition)
}
onClicked: Cura.Actions.configureSettingVisibility.trigger(definition)
}
UM.SimpleButton
@ -239,24 +265,18 @@ Button
onClicked:
{
settingDefinitionsModel.expandRecursive(definition.key);
base.checked = true;
base.showAllHiddenInheritedSettings(definition.key);
settingDefinitionsModel.expandRecursive(definition.key)
base.checked = true
base.showAllHiddenInheritedSettings(definition.key)
}
color: UM.Theme.getColor("setting_control_button")
hoverColor: UM.Theme.getColor("setting_control_button_hover")
iconSource: UM.Theme.getIcon("notice")
onEntered:
{
base.showTooltip(catalog.i18nc("@label","Some hidden settings use values different from their normal calculated value.\n\nClick to make these settings visible."))
}
onEntered: base.showTooltip(catalog.i18nc("@label","Some hidden settings use values different from their normal calculated value.\n\nClick to make these settings visible."))
onExited:
{
base.hideTooltip();
}
onExited: base.hideTooltip()
UM.I18nCatalog { id: catalog; name: "cura" }
}

View File

@ -2,9 +2,7 @@
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.3
import UM 1.2 as UM
import Cura 1.0 as Cura
@ -55,17 +53,24 @@ Item
model: UM.ToolModel { id: toolsModel }
width: childrenRect.width
height: childrenRect.height
Button
delegate: ToolbarButton
{
text: model.name + (model.shortcut ? (" (" + model.shortcut + ")") : "")
iconSource: (UM.Theme.getIcon(model.icon) != "") ? UM.Theme.getIcon(model.icon) : "file:///" + model.location + "/" + model.icon
checkable: true
checked: model.active
enabled: model.enabled && UM.Selection.hasSelection && UM.Controller.toolsEnabled
style: UM.Theme.styles.toolbar_button
property bool isFirstElement: toolsModel.getItem(0).id == model.id
property bool isLastElement: toolsModel.getItem(toolsModel.rowCount() - 1).id == model.id
isTopElement: toolsModel.getItem(0).id == model.id
isBottomElement: toolsModel.getItem(toolsModel.rowCount() - 1).id == model.id
toolItem: UM.RecolorImage
{
source: UM.Theme.getIcon(model.icon) != "" ? UM.Theme.getIcon(model.icon) : "file:///" + model.location + "/" + model.icon
color: UM.Theme.getColor("toolbar_button_text")
sourceSize: UM.Theme.getSize("button_icon")
}
onCheckedChanged:
{
@ -128,11 +133,12 @@ Item
height: childrenRect.height
property var _model: Cura.ExtrudersModel { id: extrudersModel }
model: _model.items.length > 1 ? _model : 0
ExtruderButton
delegate: ExtruderButton
{
extruder: model
height: UM.Theme.getSize("button").width
width: UM.Theme.getSize("button").width
isTopElement: extrudersModel.getItem(0).id == model.id
isBottomElement: extrudersModel.getItem(extrudersModel.rowCount() - 1).id == model.id
}
}
}

View File

@ -0,0 +1,99 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.3
import UM 1.2 as UM
import Cura 1.0 as Cura
Button
{
id: base
property alias toolItem: contentItemLoader.sourceComponent
// These two properties indicate whether the toolbar button is at the top of the toolbar column or at the bottom.
// If it is somewhere in the middle, then both has to be false. If there is only one element in the column, then
// both properties have to be set to true. This is used to create a rounded corner.
property bool isTopElement: false
property bool isBottomElement: false
hoverEnabled: true
background: Rectangle
{
implicitWidth: UM.Theme.getSize("button").width
implicitHeight: UM.Theme.getSize("button").height
color:
{
if (base.checked && base.hovered)
{
return UM.Theme.getColor("toolbar_button_active_hover")
}
else if (base.checked)
{
return UM.Theme.getColor("toolbar_button_active")
}
else if(base.hovered)
{
return UM.Theme.getColor("toolbar_button_hover")
}
return UM.Theme.getColor("toolbar_background")
}
radius: UM.Theme.getSize("default_radius").width
Rectangle
{
id: topSquare
anchors
{
left: parent.left
right: parent.right
top: parent.top
}
height: parent.radius
color: parent.color
visible: !base.isTopElement
}
Rectangle
{
id: bottomSquare
anchors
{
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: parent.radius
color: parent.color
visible: !base.isBottomElement
}
Rectangle
{
id: leftSquare
anchors
{
left: parent.left
top: parent.top
bottom: parent.bottom
}
width: parent.radius
color: parent.color
}
}
contentItem: Item
{
opacity: parent.enabled ? 1.0 : 0.2
Loader
{
id: contentItemLoader
anchors.centerIn: parent
width: UM.Theme.getSize("button_icon").width
height: UM.Theme.getSize("button_icon").height
}
}
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import UM 1.4 as UM
UM.SimpleButton
{
width: UM.Theme.getSize("small_button").width
height: UM.Theme.getSize("small_button").height
hoverBackgroundColor: UM.Theme.getColor("small_button_hover")
hoverColor: UM.Theme.getColor("small_button_text_hover")
color: UM.Theme.getColor("small_button_text")
iconMargin: 0.5 * UM.Theme.getSize("wide_lining").width
}

View File

@ -7,7 +7,7 @@ import QtQuick.Controls.Styles 1.1
import UM 1.4 as UM
// View orientation Item
// A row of buttons that control the view direction
Row
{
id: viewOrientationControl
@ -16,43 +16,33 @@ Row
height: childrenRect.height
width: childrenRect.width
// #1 3d view
Button
ViewOrientationButton
{
iconSource: UM.Theme.getIcon("view_3d")
style: UM.Theme.styles.small_tool_button
onClicked:UM.Controller.rotateView("3d", 0)
onClicked: UM.Controller.rotateView("3d", 0)
}
// #2 Front view
Button
ViewOrientationButton
{
iconSource: UM.Theme.getIcon("view_front")
style: UM.Theme.styles.small_tool_button
onClicked: UM.Controller.rotateView("home", 0)
}
// #3 Top view
Button
ViewOrientationButton
{
iconSource: UM.Theme.getIcon("view_top")
style: UM.Theme.styles.small_tool_button
onClicked: UM.Controller.rotateView("y", 90)
}
// #4 Left view
Button
ViewOrientationButton
{
iconSource: UM.Theme.getIcon("view_left")
style: UM.Theme.styles.small_tool_button
onClicked: UM.Controller.rotateView("x", 90)
}
// #5 Right view
Button
ViewOrientationButton
{
iconSource: UM.Theme.getIcon("view_right")
style: UM.Theme.styles.small_tool_button
onClicked: UM.Controller.rotateView("x", -90)
}
}

View File

@ -0,0 +1,129 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.3
import UM 1.2 as UM
import Cura 1.0 as Cura
Cura.ExpandableComponent
{
id: viewSelector
popupPadding: UM.Theme.getSize("default_lining").width
popupAlignment: Cura.ExpandableComponent.PopupAlignment.AlignLeft
iconSource: expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left")
property var viewModel: UM.ViewModel { }
property var activeView:
{
for (var i = 0; i < viewModel.rowCount(); i++)
{
if (viewModel.items[i].active)
{
return viewModel.items[i]
}
}
return null
}
Component.onCompleted:
{
// Nothing was active, so just return the first one (the list is sorted by priority, so the most
// important one should be returned)
if (activeView == null)
{
UM.Controller.setActiveView(viewModel.getItem(0).id)
}
}
headerItem: Item
{
Label
{
id: title
text: catalog.i18nc("@button", "View types")
verticalAlignment: Text.AlignVCenter
height: parent.height
elide: Text.ElideRight
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text_medium")
renderType: Text.NativeRendering
}
Label
{
text: viewSelector.activeView ? viewSelector.activeView.name : ""
verticalAlignment: Text.AlignVCenter
anchors
{
left: title.right
leftMargin: UM.Theme.getSize("default_margin").width
}
height: parent.height
elide: Text.ElideRight
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
}
}
popupItem: Column
{
id: viewSelectorPopup
width: viewSelector.width - 2 * viewSelector.popupPadding
// For some reason the height/width of the column gets set to 0 if this is not set...
Component.onCompleted:
{
height = implicitHeight
width = viewSelector.width - 2 * viewSelector.popupPadding
}
Repeater
{
id: viewsList
model: viewSelector.viewModel
delegate: Button
{
id: viewsSelectorButton
text: model.name
width: parent.width
height: UM.Theme.getSize("action_button").height
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
checkable: true
checked: viewSelector.activeView != null ? viewSelector.activeView.id == id : false
contentItem: Label
{
id: buttonText
text: viewsSelectorButton.text
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("action_button")
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle
{
id: backgroundRect
color: viewsSelectorButton.hovered ? UM.Theme.getColor("action_button_hovered") : "transparent"
radius: UM.Theme.getSize("action_button_radius").width
border.width: UM.Theme.getSize("default_lining").width
border.color: viewsSelectorButton.checked ? UM.Theme.getColor("primary") : "transparent"
}
onClicked:
{
viewSelector.togglePopup()
UM.Controller.setActiveView(id)
}
}
}
}
}

View File

@ -9,4 +9,8 @@ MaterialMenu 1.0 MaterialMenu.qml
NozzleMenu 1.0 NozzleMenu.qml
ActionPanelWidget 1.0 ActionPanelWidget.qml
IconLabel 1.0 IconLabel.qml
OutputDevicesActionButton 1.0 OutputDevicesActionButton.qml
OutputDevicesActionButton 1.0 OutputDevicesActionButton.qml
ExpandableComponent 1.0 ExpandableComponent.qml
PrinterTypeLabel 1.0 PrinterTypeLabel.qml
ViewsSelector 1.0 ViewsSelector.qml
ToolbarButton 1.0 ToolbarButton.qml

View File

@ -8,6 +8,7 @@ setting_version = 5
type = quality
quality_type = draft
weight = 0
global_quality = True
[values]
acceleration_enabled = True

View File

@ -8,6 +8,7 @@ setting_version = 5
type = quality
quality_type = high
weight = 2
global_quality = True
[values]
acceleration_enabled = True

View File

@ -8,6 +8,7 @@ setting_version = 5
type = quality
quality_type = normal
weight = 1
global_quality = True
[values]
acceleration_enabled = True

View File

@ -133,7 +133,6 @@
"slider_groove_border": [127, 127, 127, 255],
"slider_groove_fill": [245, 245, 245, 255],
"slider_handle": [255, 255, 255, 255],
"slider_handle_hover": [77, 182, 226, 255],
"slider_handle_active": [68, 192, 255, 255],
"slider_text_background": [255, 255, 255, 255],
@ -209,9 +208,6 @@
"quality_slider_unavailable": [179, 179, 179, 255],
"quality_slider_available": [255, 255, 255, 255],
"quality_slider_handle": [255, 255, 255, 255],
"quality_slider_handle_hover": [127, 127, 127, 255],
"quality_slider_text": [255, 255, 255, 255],
"toolbox_header_button_text_active": [255, 255, 255, 255],
"toolbox_header_button_text_inactive": [128, 128, 128, 255],

View File

@ -1,5 +0,0 @@
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<polygon id="Polygon" points="15 8 16 9 9 16 8 15"></polygon>
<circle id="Oval-2" cx="6" cy="18" r="4"></circle>
<circle id="Oval-2-Copy" cx="18" cy="6" r="4"></circle>
</svg>

Before

Width:  |  Height:  |  Size: 332 B

View File

@ -1,6 +0,0 @@
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle id="Oval-2" stroke="#FFFFFF" cx="4" cy="20" r="3.5"></circle>
<circle id="Oval-2-Copy" stroke="#FFFFFF" cx="20" cy="4" r="3.5"></circle>
<polygon id="Polygon" fill="#FFFFFF" points="11 12 12 13 9 16 8 15"></polygon>
<polygon id="Polygon-Copy" fill="#FFFFFF" points="15 8 16 9 13 12 12 11"></polygon>
</svg>

Before

Width:  |  Height:  |  Size: 475 B

View File

Before

Width:  |  Height:  |  Size: 878 B

After

Width:  |  Height:  |  Size: 878 B

View File

@ -1,12 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="32px" height="16px" viewBox="0 0 32 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49 (51002) - http://www.bohemiancoding.com/sketch -->
<title>icn_groupPrinters</title>
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
<title>Icon/ group printer/ disconnected</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Visual" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Printer-status-icon" transform="translate(-24.000000, -176.000000)" fill="#000000">
<path d="M48,188 L54,188 L54,190 L48,190 L48,188 L48,188 Z M48,180 L54,180 L54,182 L48,182 L48,180 L48,180 Z M54,189 L56,189 L56,191 L54,191 L54,189 L54,189 Z M54,177 L56,177 L56,189 L54,189 L54,177 L54,177 Z M48,182 L51,182 L51,183 L48,183 L48,182 L48,182 Z M49,183 L50,183 L50,185 L49,185 L49,183 L49,183 Z M48,177 L54,177 L54,179 L48,179 L48,177 L48,177 Z M34,176 L46,176 L48,176 L48,187 L53,187 L53,188 L48,188 L48,190 L48,192 L46,192 L46,191 L34,191 L34,192 L32,192 L32,190 L26,190 L26,191 L24,191 L24,189 L24,177 L26,177 L32,177 L32,176 L34,176 Z M34,178 L34,179 L46,179 L46,178 L34,178 Z M41,182 L41,184 L39,184 L39,182 L38,182 L38,181 L42,181 L42,182 L41,182 Z M46,189 L46,181 L34,181 L34,189 L46,189 Z M32,179 L26,179 L26,180 L32,180 L32,179 Z M32,183 L31,183 L31,185 L30,185 L30,183 L29,183 L29,182 L26,182 L26,188 L27,188 L27,187 L32,187 L32,183 Z M35,188 L45,188 L45,189 L35,189 L35,188 Z" id="icn_groupPrinters"></path>
<g id="Icon/-group-printer/-disconnected" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Icon/-group-printer/-connected" transform="translate(0.000000, 6.000000)">
<g id="printer-group">
<path d="M8,16.9319728 L2.15026455,16.9319728 C1.96402116,16.9492063 1.77777778,17.0181406 1.64232804,17.1387755 L1.54074074,17.2421769 C1.43915344,17.4145125 1.23597884,17.4489796 1.03280423,17.4489796 L0.118518519,17.4489796 C0.0677248677,17.4489796 0.0169312169,17.3972789 0.0169312169,17.3455782 L0.0169312169,1.09433107 C0.0169312169,1.04263039 0.0677248677,0.990929705 0.118518519,0.990929705 L8,0.990929705 L8,2.47301587 L1.86243386,2.47301587 C1.67619048,2.47301587 1.54074074,2.62811791 1.54074074,2.80045351 L1.54074074,13.4680272 C1.54074074,13.9505669 1.93015873,14.3469388 2.4042328,14.3469388 L8,14.3469388 L8,16.9319728 Z" id="Combined-Shape" fill="#08073F" fill-rule="nonzero"></path>
<g id="UM3" transform="translate(23.777778, 0.904762)"></g>
<path d="M24,0.990929705 L31.8814815,0.990929705 C31.9322751,0.990929705 31.9830688,1.04263039 31.9830688,1.09433107 L31.9830688,17.3455782 C31.9830688,17.3972789 31.9322751,17.4489796 31.8814815,17.4489796 L30.9671958,17.4489796 C30.7809524,17.431746 30.594709,17.3628118 30.4592593,17.2421769 L30.357672,17.1387755 C30.2560847,16.9664399 30.0529101,16.9319728 29.8497354,16.9319728 L24,16.9319728 L24,14.3469388 L29.5619048,14.3469388 C30.0359788,14.3469388 30.4253968,13.9505669 30.4253968,13.4680272 L30.442328,13.4680272 L30.442328,2.80045351 C30.442328,2.61088435 30.2899471,2.47301587 30.1206349,2.47301587 L24,2.47301587 L24,0.990929705 Z" id="Combined-Shape" fill="#08073F" fill-rule="nonzero"></path>
<g id="Group-Copy-2" transform="translate(8.000000, 0.000000)" fill="#08073F" fill-rule="nonzero">
<g id="UM3" transform="translate(0.000000, 0.000000)">
<path d="M15.8666667,0.0969387755 L0.133333333,0.0969387755 C0.0761904762,0.0969387755 0.019047619,0.155102041 0.019047619,0.213265306 L0.019047619,18.4959184 C0.019047619,18.5540816 0.0761904762,18.6122449 0.133333333,18.6122449 L1.16190476,18.6122449 C1.39047619,18.6122449 1.61904762,18.5734694 1.73333333,18.3795918 L1.84761905,18.2632653 C2,18.127551 2.20952381,18.05 2.41904762,18.0306122 L13.5809524,18.0306122 C13.8095238,18.0306122 14.0380952,18.0693878 14.152381,18.2632653 L14.2666667,18.3795918 C14.4190476,18.5153061 14.6285714,18.5928571 14.8380952,18.6122449 L15.8666667,18.6122449 C15.9238095,18.6122449 15.9809524,18.5540816 15.9809524,18.4959184 L15.9809524,0.213265306 C15.9809524,0.155102041 15.9238095,0.0969387755 15.8666667,0.0969387755 Z M14.2285714,14.1336735 C14.2285714,14.6765306 13.7904762,15.122449 13.2571429,15.122449 L2.7047619,15.122449 C2.17142857,15.122449 1.73333333,14.6765306 1.73333333,14.1336735 L1.73333333,2.13265306 C1.73333333,1.93877551 1.88571429,1.76428571 2.0952381,1.76428571 L13.8857143,1.76428571 C14.0761905,1.76428571 14.247619,1.91938776 14.247619,2.13265306 L14.247619,14.1336735 L14.2285714,14.1336735 Z" id="Shape"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49 (51002) - http://www.bohemiancoding.com/sketch -->
<title>icn_singlePrinter</title>
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
<title>Icon/ single printer/ disconnected</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Visual" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Printer-status-icon" transform="translate(-217.000000, -176.000000)" fill="#000000">
<g id="icn_singlePrinter" transform="translate(217.000000, 176.000000)">
<path d="M2,13 L14,13 L14,15 L2,15 L2,13 L2,13 Z M2,3 L14,3 L14,5 L2,5 L2,3 L2,3 Z M0,14 L2,14 L2,16 L0,16 L0,14 L0,14 Z M14,14 L16,14 L16,16 L14,16 L14,14 L14,14 Z M0,0 L2,0 L2,14 L0,14 L0,0 L0,0 Z M14,0 L16,0 L16,14 L14,14 L14,0 L14,0 Z M6,5 L10,5 L10,6 L6,6 L6,5 L6,5 Z M7,6 L9,6 L9,8 L7,8 L7,6 L7,6 Z M2,0 L14,0 L14,2 L2,2 L2,0 L2,0 Z M3,12 L13,12 L13,13 L3,13 L3,12 L3,12 Z" id="Rectangle-185-Copy-5-Copy-4"></path>
<g id="Icon/-single-printer/-disconnected" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group-Copy-7" transform="translate(6.000000, 5.000000)" fill="#08073F" fill-rule="nonzero">
<g id="UM3" transform="translate(0.000000, 0.000000)">
<path d="M19.8333333,0.119047619 L0.166666667,0.119047619 C0.0952380952,0.119047619 0.0238095238,0.19047619 0.0238095238,0.261904762 L0.0238095238,22.7142857 C0.0238095238,22.7857143 0.0952380952,22.8571429 0.166666667,22.8571429 L1.45238095,22.8571429 C1.73809524,22.8571429 2.02380952,22.8095238 2.16666667,22.5714286 L2.30952381,22.4285714 C2.5,22.2619048 2.76190476,22.1666667 3.02380952,22.1428571 L16.9761905,22.1428571 C17.2619048,22.1428571 17.547619,22.1904762 17.6904762,22.4285714 L17.8333333,22.5714286 C18.0238095,22.7380952 18.2857143,22.8333333 18.547619,22.8571429 L19.8333333,22.8571429 C19.9047619,22.8571429 19.9761905,22.7857143 19.9761905,22.7142857 L19.9761905,0.261904762 C19.9761905,0.19047619 19.9047619,0.119047619 19.8333333,0.119047619 Z M17.7857143,17.3571429 C17.7857143,18.0238095 17.2380952,18.5714286 16.5714286,18.5714286 L3.38095238,18.5714286 C2.71428571,18.5714286 2.16666667,18.0238095 2.16666667,17.3571429 L2.16666667,2.61904762 C2.16666667,2.38095238 2.35714286,2.16666667 2.61904762,2.16666667 L17.3571429,2.16666667 C17.5952381,2.16666667 17.8095238,2.35714286 17.8095238,2.61904762 L17.8095238,17.3571429 L17.7857143,17.3571429 Z" id="Shape"></path>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Busy</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="00-printer-status-overview" transform="translate(-17.000000, -22.000000)"></g>
<g id="Busy" fill="#D8D8D8">
<path d="M7,14 C3.13400675,14 0,10.8659932 0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 Z M9.5,7 C9.5,7.83420277 10.1715729,8.5 11,8.5 C11.8342028,8.5 12.5,7.82842712 12.5,7 C12.5,6.16579723 11.8284271,5.5 11,5.5 C10.1657972,5.5 9.5,6.17157288 9.5,7 Z M1.5,7 C1.5,7.83420277 2.17157288,8.5 3,8.5 C3.83420277,8.5 4.5,7.82842712 4.5,7 C4.5,6.16579723 3.82842712,5.5 3,5.5 C2.16579723,5.5 1.5,6.17157288 1.5,7 Z M5.5,7 C5.5,7.83420277 6.17157288,8.5 7,8.5 C7.83420277,8.5 8.5,7.82842712 8.5,7 C8.5,6.16579723 7.82842712,5.5 7,5.5 C6.16579723,5.5 5.5,6.17157288 5.5,7 Z" id="Combined-Shape"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Wait cleanup</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="00-printer-status-overview" transform="translate(-84.000000, -22.000000)"></g>
<g id="Wait-cleanup" fill="#7FDB16">
<path d="M7,14 C3.13400675,14 0,10.8659932 0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 Z M8.07520384,11.2263517 L8.07520384,10.7137766 C8.07520384,10.2581543 7.84739269,10.0018668 7.36329399,10.0018668 L6.73681332,10.0018668 C6.28119101,10.0018668 6.02490346,10.2296779 6.02490346,10.7137766 L6.02490346,11.2263517 C6.02490346,11.681974 6.25271461,11.9382616 6.73681332,11.9382616 L7.36329399,11.9382616 C7.8189163,11.9382616 8.07520384,11.7104504 8.07520384,11.2263517 Z M8.04672745,7.78070802 L8.21758581,2.74038625 C8.21758581,2.25628755 7.98977466,2 7.50567596,2 L6.59443134,2 C6.11033264,2 5.88252149,2.25628755 5.88252149,2.74038625 L6.05337986,7.78070802 C6.08185625,8.23633033 6.3381438,8.49261788 6.7937661,8.49261788 L7.3063412,8.49261788 C7.76196351,8.49261788 8.04672745,8.23633033 8.04672745,7.78070802 Z" id="Combined-Shape"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>paused</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="00-printer-status-overview" transform="translate(-246.000000, -22.000000)"></g>
<g id="paused" fill="#F5A623">
<path d="M7,14 C3.13400675,14 0,10.8659932 0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 Z M4.33333333,4.11111111 L4.33333333,9.88888889 L6.11111111,9.88888889 L6.11111111,4.11111111 L4.33333333,4.11111111 Z M7.88888889,4.11111111 L7.88888889,9.88888889 L9.66666667,9.88888889 L9.66666667,4.11111111 L7.88888889,4.11111111 Z" id="Combined-Shape"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1016 B

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Aborted</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="00-printer-status-overview" transform="translate(-303.000000, -22.000000)"></g>
<g id="Aborted" fill="#D0021B">
<path d="M7.006431,8.15087791 L8.99372277,9.86752475 L10.1369901,8.54194059 L8.1500273,6.82616116 L9.86540931,4.83910045 L8.54098909,3.69576014 L6.82576597,5.68263681 L4.8380396,3.96619802 L3.69512871,5.29053465 L5.6823619,7.00713089 L3.96564795,8.9957345 L5.29006817,10.1390748 L7.006431,8.15087791 Z M7,14 C3.13400675,14 0,10.8659932 0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 Z" id="Combined-Shape"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Unknown</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="00-printer-status-overview" transform="translate(-165.000000, -22.000000)"></g>
<g id="Unknown" fill="#000000">
<path d="M7,14 C3.13400675,14 0,10.8659932 0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 Z M6.78333984,11.3842884 C7.41672998,11.3842884 7.93020964,10.8704803 7.93020964,10.2374186 C7.93020964,9.60435702 7.41672998,9.09087736 6.78333984,9.09087736 C6.1499497,9.09087736 5.63647003,9.6040285 5.63647003,10.2374186 C5.63647003,10.8708088 6.1499497,11.3842884 6.78333984,11.3842884 Z M7.5343408,7.73605322 C8.81853274,7.61975648 9.82775188,6.53727696 9.82808041,5.22351806 C9.82808041,3.83222799 8.69632261,2.7004702 7.30503254,2.7004702 C5.91374248,2.7004702 4.78198468,3.83255652 4.78198468,5.22351806 L6.33589307,5.22351806 C6.33589307,4.68967004 6.77052748,4.25503562 7.30470402,4.25503562 C7.83920908,4.25503562 8.27351498,4.68967004 8.27351498,5.22351806 C8.27351498,5.75802312 7.83920908,6.19232901 7.30470402,6.19232901 L5.9801039,6.19232901 L5.9801039,8.54355994 L7.5343408,8.54355994 L7.5343408,7.73605322 Z" id="Combined-Shape"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 310 KiB

View File

@ -171,123 +171,6 @@ QtObject
}
}
property Component toolbar_button: Component
{
ButtonStyle
{
background: Rectangle
{
implicitWidth: Theme.getSize("button").width
implicitHeight: Theme.getSize("button").height
color:
{
if (control.checked && control.hovered)
{
return Theme.getColor("toolbar_button_active_hover")
}
else if (control.checked)
{
return Theme.getColor("toolbar_button_active")
}
else if(control.hovered)
{
return Theme.getColor("toolbar_button_hover")
}
return Theme.getColor("toolbar_background")
}
radius: UM.Theme.getSize("default_radius").width
Rectangle
{
id: topSquare
anchors
{
left: parent.left
right: parent.right
top: parent.top
}
height: parent.radius
color: control.isFirstElement ? "transparent" : parent.color
}
Rectangle
{
id: bottomSquare
anchors
{
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: parent.radius
color: control.isLastElement ? "transparent" : parent.color
}
Rectangle
{
id: leftSquare
anchors
{
left: parent.left
top: parent.top
bottom: parent.bottom
}
width: parent.radius
color: parent.color
}
// This is the tooltip
UM.PointingRectangle
{
id: button_tooltip
anchors.left: parent.right
anchors.leftMargin: Theme.getSize("button_tooltip_arrow").width * 2
anchors.verticalCenter: parent.verticalCenter
target: Qt.point(parent.x, y + Math.round(height/2))
arrowSize: Theme.getSize("button_tooltip_arrow").width
color: Theme.getColor("button_tooltip")
opacity: control.hovered ? 1.0 : 0.0;
visible: control.text != ""
width: control.hovered ? button_tip.width + Theme.getSize("button_tooltip").width : 0
height: Theme.getSize("button_tooltip").height
Behavior on width { NumberAnimation { duration: 100; } }
Behavior on opacity { NumberAnimation { duration: 100; } }
Label
{
id: button_tip
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter;
text: control.text;
font: Theme.getFont("button_tooltip");
color: Theme.getColor("tooltip_text");
}
}
}
label: Item
{
UM.RecolorImage
{
anchors.centerIn: parent;
opacity: !control.enabled ? 0.2 : 1.0
source: control.iconSource;
width: Theme.getSize("button_icon").width;
height: Theme.getSize("button_icon").height;
color: Theme.getColor("toolbar_button_text");
sourceSize: Theme.getSize("button_icon")
}
}
}
}
property Component tool_button: Component
{
ButtonStyle
@ -436,118 +319,6 @@ QtObject
}
}
property Component small_tool_button: Component
{
ButtonStyle
{
background: Item
{
implicitWidth: Theme.getSize("small_button").width;
implicitHeight: Theme.getSize("small_button").height;
Rectangle
{
id: smallButtonFace;
anchors.fill: parent;
property bool down: control.pressed || (control.checkable && control.checked);
color:
{
if(control.customColor !== undefined && control.customColor !== null)
{
return control.customColor
}
else if(control.checkable && control.checked && control.hovered)
{
return Theme.getColor("small_button_active_hover");
}
else if(control.pressed || (control.checkable && control.checked))
{
return Theme.getColor("small_button_active");
}
else if(control.hovered)
{
return Theme.getColor("small_button_hover");
}
else
{
return Theme.getColor("small_button");
}
}
Behavior on color { ColorAnimation { duration: 50; } }
border.width: (control.hasOwnProperty("needBorder") && control.needBorder) ? 2 * screenScaleFactor : 0
border.color: Theme.getColor("tool_button_border")
UM.RecolorImage
{
id: smallToolButtonArrow
width: 5
height: 5
sourceSize.width: 5
sourceSize.height: 5
visible: control.menu != null;
color:
{
if(control.checkable && control.checked && control.hovered)
{
return Theme.getColor("small_button_text_active_hover");
}
else if(control.pressed || (control.checkable && control.checked))
{
return Theme.getColor("small_button_text_active");
}
else if(control.hovered)
{
return Theme.getColor("small_button_text_hover");
}
else
{
return Theme.getColor("small_button_text");
}
}
source: Theme.getIcon("arrow_bottom")
}
}
}
label: Item
{
UM.RecolorImage
{
anchors.centerIn: parent
opacity: !control.enabled ? 0.2 : 1.0
source: control.iconSource;
width: Theme.getSize("small_button_icon").width
height: Theme.getSize("small_button_icon").height
color:
{
if(control.checkable && control.checked && control.hovered)
{
return Theme.getColor("small_button_text_active_hover");
}
else if(control.pressed || (control.checkable && control.checked))
{
return Theme.getColor("small_button_text_active");
}
else if(control.hovered)
{
return Theme.getColor("small_button_text_hover");
}
else
{
return Theme.getColor("small_button_text");
}
}
sourceSize: Theme.getSize("small_button_icon")
}
}
}
}
property Component progressbar: Component
{
ProgressBarStyle
@ -599,198 +370,6 @@ QtObject
}
}
property Component sidebar_category: Component
{
ButtonStyle
{
background: Rectangle
{
anchors.fill: parent
anchors.left: parent.left
anchors.leftMargin: Theme.getSize("thick_margin").width
anchors.right: parent.right
anchors.rightMargin: Theme.getSize("thick_margin").width
implicitHeight: Theme.getSize("section").height
color:
{
if(control.color)
{
return control.color;
}
else if(!control.enabled)
{
return Theme.getColor("setting_category_disabled");
}
else if(control.hovered && control.checkable && control.checked)
{
return Theme.getColor("setting_category_active_hover");
}
else if(control.pressed || (control.checkable && control.checked))
{
return Theme.getColor("setting_category_active");
}
else if(control.hovered)
{
return Theme.getColor("setting_category_hover");
}
else
{
return Theme.getColor("setting_category");
}
}
Behavior on color { ColorAnimation { duration: 50; } }
Rectangle
{
height: Theme.getSize("default_lining").height
width: parent.width
anchors.bottom: parent.bottom
color:
{
if(!control.enabled)
{
return Theme.getColor("setting_category_disabled_border");
}
else if((control.hovered || control.activeFocus) && control.checkable && control.checked)
{
return Theme.getColor("setting_category_active_hover_border");
}
else if(control.pressed || (control.checkable && control.checked))
{
return Theme.getColor("setting_category_active_border");
}
else if(control.hovered || control.activeFocus)
{
return Theme.getColor("setting_category_hover_border");
}
else
{
return Theme.getColor("setting_category_border");
}
}
}
}
label: Item
{
anchors.fill: parent
anchors.left: parent.left
Item
{
id: icon
anchors.left: parent.left
height: parent.height
width: Theme.getSize("section_icon_column").width
UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Theme.getSize("thick_margin").width
color:
{
if(!control.enabled)
{
return Theme.getColor("setting_category_disabled_text");
}
else if((control.hovered || control.activeFocus) && control.checkable && control.checked)
{
return Theme.getColor("setting_category_active_hover_text");
}
else if(control.pressed || (control.checkable && control.checked))
{
return Theme.getColor("setting_category_active_text");
}
else if(control.hovered || control.activeFocus)
{
return Theme.getColor("setting_category_hover_text");
}
else
{
return Theme.getColor("setting_category_text");
}
}
source: control.iconSource;
width: Theme.getSize("section_icon").width;
height: Theme.getSize("section_icon").height;
sourceSize.width: width + 15 * screenScaleFactor
sourceSize.height: width + 15 * screenScaleFactor
}
}
Label
{
anchors
{
left: icon.right
leftMargin: Theme.getSize("default_margin").width
right: parent.right
verticalCenter: parent.verticalCenter
}
text: control.text
font: Theme.getFont("setting_category")
color:
{
if(!control.enabled)
{
return Theme.getColor("setting_category_disabled_text");
}
else if((control.hovered || control.activeFocus) && control.checkable && control.checked)
{
return Theme.getColor("setting_category_active_hover_text");
}
else if(control.pressed || (control.checkable && control.checked))
{
return Theme.getColor("setting_category_active_text");
}
else if(control.hovered || control.activeFocus)
{
return Theme.getColor("setting_category_hover_text");
}
else
{
return Theme.getColor("setting_category_text");
}
}
fontSizeMode: Text.HorizontalFit
minimumPointSize: 8
}
UM.RecolorImage
{
id: category_arrow
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: Theme.getSize("default_margin").width * 3 - Math.round(width / 2)
width: Theme.getSize("standard_arrow").width
height: Theme.getSize("standard_arrow").height
sourceSize.width: width
sourceSize.height: width
color:
{
if(!control.enabled)
{
return Theme.getColor("setting_category_disabled_text");
}
else if((control.hovered || control.activeFocus) && control.checkable && control.checked)
{
return Theme.getColor("setting_category_active_hover_text");
}
else if(control.pressed || (control.checkable && control.checked))
{
return Theme.getColor("setting_category_active_text");
}
else if(control.hovered || control.activeFocus)
{
return Theme.getColor("setting_category_hover_text");
}
else
{
return Theme.getColor("setting_category_text");
}
}
source: control.checked ? Theme.getIcon("arrow_bottom") : Theme.getIcon("arrow_left")
}
}
}
}
property Component scrollview: Component
{
ScrollViewStyle
@ -1144,60 +723,4 @@ QtObject
label: Item { }
}
}
property Component toolbox_action_button: Component
{
ButtonStyle
{
background: Rectangle
{
implicitWidth: UM.Theme.getSize("toolbox_action_button").width
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
color:
{
if (control.installed)
{
return UM.Theme.getColor("action_button_disabled");
}
else
{
if (control.hovered)
{
return UM.Theme.getColor("primary_hover");
}
else
{
return UM.Theme.getColor("primary");
}
}
}
}
label: Label
{
text: control.text
color:
{
if (control.installed)
{
return UM.Theme.getColor("action_button_disabled_text");
}
else
{
if (control.hovered)
{
return UM.Theme.getColor("button_text_hover");
}
else
{
return UM.Theme.getColor("button_text");
}
}
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font: UM.Theme.getFont("default_bold")
}
}
}
}

View File

@ -81,14 +81,26 @@
"lining": [192, 193, 194, 255],
"viewport_overlay": [0, 0, 0, 192],
"primary": [50, 130, 255, 255],
"primary_shadow": [64, 47, 205, 255],
"primary_hover": [48, 182, 231, 255],
"primary_text": [255, 255, 255, 255],
"border": [127, 127, 127, 255],
"secondary": [245, 245, 245, 255],
"secondary": [240, 240, 240, 255],
"secondary_shadow": [216, 216, 216, 255],
"primary_button": [38, 113, 231, 255],
"primary_button_shadow": [27, 95, 202, 255],
"primary_button_hover": [81, 145, 247, 255],
"primary_button_text": [255, 255, 255, 255],
"secondary_button": [240, 240, 240, 255],
"secondary_button_shadow": [216, 216, 216, 255],
"secondary_button_hover": [228, 228, 228, 255],
"secondary_button_text": [30, 102, 215, 255],
"main_window_header_background": [10, 8, 80, 255],
"main_window_header_background_gradient": [25, 23, 91, 255],
"main_window_header_button_text_active": [10, 8, 80, 255],
"main_window_header_button_text_inactive": [255, 255, 255, 255],
"main_window_header_button_text_hovered": [255, 255, 255, 255],
@ -96,13 +108,6 @@
"main_window_header_button_background_inactive": [255, 255, 255, 0],
"main_window_header_button_background_hovered": [255, 255, 255, 102],
"main_window_header_secondary_button_text_active": [255, 255, 255, 255],
"main_window_header_secondary_button_text_hovered": [10, 8, 80, 255],
"main_window_header_secondary_button_background_active": [255, 255, 255, 0],
"main_window_header_secondary_button_background_hovered": [255, 255, 255, 255],
"main_window_header_secondary_button_outline_active": [255, 255, 255, 255],
"main_window_header_secondary_button_outline_hovered": [255, 255, 255, 255],
"account_widget_outline_active": [70, 66, 126, 255],
"machine_selector_bar": [31, 36, 39, 255],
@ -114,11 +119,12 @@
"toolbar_background": [255, 255, 255, 255],
"printer_type_label_background": [171, 171, 191, 255],
"text": [0, 0, 0, 255],
"text_detail": [174, 174, 174, 128],
"text_link": [50, 130, 255, 255],
"text_inactive": [174, 174, 174, 255],
"text_hover": [70, 84, 113, 255],
"text_pressed": [50, 130, 255, 255],
"text_subtext": [0, 0, 0, 255],
"text_medium": [128, 128, 128, 255],
@ -173,14 +179,8 @@
"action_button_disabled": [245, 245, 245, 255],
"action_button_disabled_text": [127, 127, 127, 255],
"action_button_disabled_border": [245, 245, 245, 255],
"print_button_ready": [50, 130, 255, 255],
"print_button_ready_border": [50, 130, 255, 255],
"print_button_ready_text": [255, 255, 255, 255],
"print_button_ready_hovered": [30, 186, 245, 243],
"print_button_ready_hovered_border": [30, 186, 245, 243],
"print_button_ready_pressed": [30, 186, 245, 243],
"print_button_ready_pressed_border": [30, 186, 245, 243],
"action_button_shadow": [223, 223, 223, 255],
"action_button_disabled_shadow": [228, 228, 228, 255],
"scrollbar_background": [255, 255, 255, 255],
"scrollbar_handle": [31, 36, 39, 255],
@ -230,15 +230,11 @@
"slider_groove": [223, 223, 223, 255],
"slider_groove_fill": [10, 8, 80, 255],
"slider_handle": [10, 8, 80, 255],
"slider_handle_hover": [77, 182, 226, 255],
"slider_handle_active": [50, 130, 255, 255],
"slider_text_background": [255, 255, 255, 255],
"quality_slider_unavailable": [179, 179, 179, 255],
"quality_slider_available": [0, 0, 0, 255],
"quality_slider_handle": [0, 0, 0, 255],
"quality_slider_handle_hover": [127, 127, 127, 255],
"quality_slider_text": [0, 0, 0, 255],
"checkbox": [255, 255, 255, 255],
"checkbox_hover": [255, 255, 255, 255],
@ -247,15 +243,6 @@
"checkbox_mark": [119, 122, 124, 255],
"checkbox_text": [27, 27, 27, 255],
"mode_switch": [255, 255, 255, 255],
"mode_switch_hover": [255, 255, 255, 255],
"mode_switch_border": [127, 127, 127, 255],
"mode_switch_border_hover": [50, 130, 255, 255],
"mode_switch_handle": [31, 36, 39, 255],
"mode_switch_text": [31, 36, 39, 255],
"mode_switch_text_hover": [31, 36, 39, 255],
"mode_switch_text_checked": [50, 130, 255, 255],
"tooltip": [68, 192, 255, 255],
"tooltip_text": [255, 255, 255, 255],
@ -373,11 +360,11 @@
"sizes": {
"window_minimum_size": [106, 66],
"main_window_header": [0.0, 4.5],
"main_window_header": [0.0, 4.0],
"main_window_header_button": [8, 2.35],
"main_window_header_button_icon": [1.2, 1.2],
"stage_menu": [0.0, 4.5],
"stage_menu": [0.0, 4.0],
"account_button": [12, 3],
@ -386,17 +373,20 @@
"print_setup_item": [0.0, 2.0],
"print_setup_extruder_box": [0.0, 6.0],
"configuration_selector_widget": [35.0, 4.5],
"configuration_selector_mode_tabs": [0.0, 3.0],
"action_panel_widget": [25.0, 0.0],
"action_panel_information_widget": [20.0, 0.0],
"action_panel_button": [15.0, 3.0],
"machine_selector_widget": [16.0, 4.5],
"machine_selector_widget": [20.0, 4.0],
"machine_selector_widget_content": [25.0, 32.0],
"machine_selector_icon": [2.66, 2.66],
"views_selector": [16.0, 4.5],
"printer_type_label": [3.5, 1.5],
"default_radius": [0.25, 0.25],
"wide_lining": [0.5, 0.5],
@ -412,10 +402,7 @@
"thin_margin": [0.71, 0.71],
"narrow_margin": [0.5, 0.5],
"extruder_icon": [1.8, 1.8],
"simple_mode_infill_caption": [0.0, 5.0],
"simple_mode_infill_height": [0.0, 8.0],
"extruder_icon": [2.33, 2.33],
"section": [0.0, 2.2],
"section_icon": [1.6, 1.6],
@ -430,7 +417,6 @@
"setting_text_maxwidth": [40.0, 0.0],
"standard_list_lineheight": [1.5, 1.5],
"standard_list_input": [20.0, 25.0],
"standard_arrow": [0.8, 0.8],
"button": [4, 4],
@ -444,7 +430,7 @@
"favorites_button": [2, 2],
"favorites_button_icon": [1.2, 1.2],
"printer_status_icon": [1.8, 1.8],
"printer_status_icon": [1.0, 1.0],
"printer_sync_icon": [1.2, 1.2],
"button_tooltip": [1.0, 1.3],
@ -525,6 +511,7 @@
"avatar_image": [6.8, 6.8],
"action_button": [15.0, 3.0],
"action_button_radius": [0.15, 0.15],
"monitor_config_override_box": [1.0, 14.0],

View File

@ -1,5 +1,7 @@
import functools
from cura import PrintInformation
from cura.Settings.MachineManager import MachineManager
from unittest.mock import MagicMock, patch
from UM.Application import Application
@ -11,14 +13,20 @@ def getPrintInformation(printer_name) -> PrintInformation:
mock_application = MagicMock()
global_container_stack = MagicMock()
global_container_stack.definition.getName = MagicMock(return_value=printer_name)
mock_application.getGlobalContainerStack = MagicMock(return_value=global_container_stack)
global_container_stack.definition.getName = MagicMock(return_value = printer_name)
mock_application.getGlobalContainerStack = MagicMock(return_value = global_container_stack)
multiBuildPlateModel = MagicMock()
multiBuildPlateModel.maxBuildPlate = 0
mock_application.getMultiBuildPlateModel = MagicMock(return_value=multiBuildPlateModel)
multi_build_plate_model = MagicMock()
multi_build_plate_model.maxBuildPlate = 0
mock_application.getMultiBuildPlateModel = MagicMock(return_value = multi_build_plate_model)
Application.getInstance = MagicMock(return_type=mock_application)
# Mock-up the entire machine manager except the function that needs to be tested: getAbbreviatedMachineName
original_get_abbreviated_name = MachineManager.getAbbreviatedMachineName
mock_machine_manager = MagicMock()
mock_machine_manager.getAbbreviatedMachineName = functools.partial(original_get_abbreviated_name, mock_machine_manager)
mock_application.getMachineManager = MagicMock(return_value = mock_machine_manager)
Application.getInstance = MagicMock(return_type = mock_application)
with patch("json.loads", lambda x: {}):
print_information = PrintInformation.PrintInformation(mock_application)
@ -28,17 +36,17 @@ def getPrintInformation(printer_name) -> PrintInformation:
def setup_module():
MimeTypeDatabase.addMimeType(
MimeType(
name="application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
comment="3MF",
suffixes=["3mf"]
name = "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
comment = "3MF",
suffixes = ["3mf"]
)
)
MimeTypeDatabase.addMimeType(
MimeType(
name="application/x-cura-gcode-file",
comment="Cura GCode File",
suffixes=["gcode"]
name = "application/x-cura-gcode-file",
comment = "Cura GCode File",
suffixes = ["gcode"]
)
)
@ -49,42 +57,42 @@ def test_setProjectName():
print_information = getPrintInformation("ultimaker")
# Test simple name
project_name = ["HelloWorld",".3mf"]
project_name = ["HelloWorld", ".3mf"]
print_information.setProjectName(project_name[0] + project_name[1])
assert "UM_" + project_name[0] == print_information._job_name
# Test the name with one dot
project_name = ["Hello.World",".3mf"]
project_name = ["Hello.World", ".3mf"]
print_information.setProjectName(project_name[0] + project_name[1])
assert "UM_" + project_name[0] == print_information._job_name
# Test the name with two dot
project_name = ["Hello.World.World",".3mf"]
project_name = ["Hello.World.World", ".3mf"]
print_information.setProjectName(project_name[0] + project_name[1])
assert "UM_" + project_name[0] == print_information._job_name
# Test the name with dot at the beginning
project_name = [".Hello.World",".3mf"]
project_name = [".Hello.World", ".3mf"]
print_information.setProjectName(project_name[0] + project_name[1])
assert "UM_" + project_name[0] == print_information._job_name
# Test the name with underline
project_name = ["Hello_World",".3mf"]
project_name = ["Hello_World", ".3mf"]
print_information.setProjectName(project_name[0] + project_name[1])
assert "UM_" + project_name[0] == print_information._job_name
# Test gcode extension
project_name = ["Hello_World",".gcode"]
project_name = ["Hello_World", ".gcode"]
print_information.setProjectName(project_name[0] + project_name[1])
assert "UM_" + project_name[0] == print_information._job_name
# Test empty project name
project_name = ["",""]
project_name = ["", ""]
print_information.setProjectName(project_name[0] + project_name[1])
assert print_information.UNTITLED_JOB_NAME == print_information._job_name
# Test wrong file extension
project_name = ["Hello_World",".test"]
project_name = ["Hello_World", ".test"]
print_information.setProjectName(project_name[0] + project_name[1])
assert "UM_" + project_name[0] != print_information._job_name
@ -93,7 +101,7 @@ def test_setJobName():
print_information = getPrintInformation("ultimaker")
print_information._abbr_machine = "UM"
print_information.setJobName("UM_HelloWorld", is_user_specified_job_name=False)
print_information.setJobName("UM_HelloWorld", is_user_specified_job_name = False)
def test_defineAbbreviatedMachineName():
@ -102,6 +110,6 @@ def test_defineAbbreviatedMachineName():
print_information = getPrintInformation(printer_name)
# Test not ultimaker printer, name suffix should have first letter from the printer name
project_name = ["HelloWorld",".3mf"]
project_name = ["HelloWorld", ".3mf"]
print_information.setProjectName(project_name[0] + project_name[1])
assert printer_name[0] + "_" + project_name[0] == print_information._job_name