Merge branch 'master' into container_stack_improvements

This commit is contained in:
ChrisTerBeke 2017-11-06 09:49:44 +01:00
commit d32b7f0091
19 changed files with 616 additions and 57 deletions

1
.gitignore vendored
View File

@ -43,6 +43,7 @@ plugins/ProfileFlattener
plugins/cura-god-mode-plugin plugins/cura-god-mode-plugin
plugins/cura-big-flame-graph plugins/cura-big-flame-graph
plugins/cura-siemensnx-plugin plugins/cura-siemensnx-plugin
plugins/CuraVariSlicePlugin
#Build stuff #Build stuff
CMakeCache.txt CMakeCache.txt

View File

@ -56,6 +56,7 @@ class PrintInformation(QObject):
self._material_lengths = [] self._material_lengths = []
self._material_weights = [] self._material_weights = []
self._material_costs = [] self._material_costs = []
self._material_names = []
self._pre_sliced = False self._pre_sliced = False
@ -139,6 +140,12 @@ class PrintInformation(QObject):
def materialCosts(self): def materialCosts(self):
return self._material_costs return self._material_costs
materialNamesChanged = pyqtSignal()
@pyqtProperty("QVariantList", notify = materialNamesChanged)
def materialNames(self):
return self._material_names
def _onPrintDurationMessage(self, print_time, material_amounts): def _onPrintDurationMessage(self, print_time, material_amounts):
self._updateTotalPrintTimePerFeature(print_time) self._updateTotalPrintTimePerFeature(print_time)
@ -170,6 +177,7 @@ class PrintInformation(QObject):
self._material_lengths = [] self._material_lengths = []
self._material_weights = [] self._material_weights = []
self._material_costs = [] self._material_costs = []
self._material_names = []
material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings")) material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings"))
@ -188,8 +196,10 @@ class PrintInformation(QObject):
weight = float(amount) * float(density) / 1000 weight = float(amount) * float(density) / 1000
cost = 0 cost = 0
material_name = catalog.i18nc("@label unknown material", "Unknown")
if material: if material:
material_guid = material.getMetaDataEntry("GUID") material_guid = material.getMetaDataEntry("GUID")
material_name = material.getName()
if material_guid in material_preference_values: if material_guid in material_preference_values:
material_values = material_preference_values[material_guid] material_values = material_preference_values[material_guid]
@ -208,10 +218,12 @@ class PrintInformation(QObject):
self._material_weights.append(weight) self._material_weights.append(weight)
self._material_lengths.append(length) self._material_lengths.append(length)
self._material_costs.append(cost) self._material_costs.append(cost)
self._material_names.append(material_name)
self.materialLengthsChanged.emit() self.materialLengthsChanged.emit()
self.materialWeightsChanged.emit() self.materialWeightsChanged.emit()
self.materialCostsChanged.emit() self.materialCostsChanged.emit()
self.materialNamesChanged.emit()
def _onPreferencesChanged(self, preference): def _onPreferencesChanged(self, preference):
if preference != "cura/material_settings": if preference != "cura/material_settings":

View File

@ -74,6 +74,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._can_pause = True self._can_pause = True
self._can_abort = True self._can_abort = True
self._can_pre_heat_bed = True self._can_pre_heat_bed = True
self._can_control_manually = True
def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None): def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None):
raise NotImplementedError("requestWrite needs to be implemented") raise NotImplementedError("requestWrite needs to be implemented")
@ -144,6 +145,11 @@ class PrinterOutputDevice(QObject, OutputDevice):
def canAbort(self): def canAbort(self):
return self._can_abort return self._can_abort
# Does the printer support manual control at all
@pyqtProperty(bool, constant=True)
def canControlManually(self):
return self._can_control_manually
@pyqtProperty(QObject, constant=True) @pyqtProperty(QObject, constant=True)
def monitorItem(self): def monitorItem(self):
# Note that we specifically only check if the monitor component is created. # Note that we specifically only check if the monitor component is created.

View File

@ -293,7 +293,7 @@ class CuraEngineBackend(QObject, Backend):
error_labels.add(definitions[0].label) error_labels.add(definitions[0].label)
error_labels = ", ".join(error_labels) error_labels = ", ".join(error_labels)
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. The following settings have errors: {0}".format(error_labels)), self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. The following settings have errors: {0}").format(error_labels),
title = catalog.i18nc("@info:title", "Unable to slice")) title = catalog.i18nc("@info:title", "Unable to slice"))
self._error_message.show() self._error_message.show()
self.backendStateChange.emit(BackendState.Error) self.backendStateChange.emit(BackendState.Error)

View File

@ -112,7 +112,6 @@ class LayerView(View):
self._layer_pass = LayerPass.LayerPass(1, 1) self._layer_pass = LayerPass.LayerPass(1, 1)
self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode")) self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode"))
self._layer_pass.setLayerView(self) self._layer_pass.setLayerView(self)
self.getRenderer().addRenderPass(self._layer_pass)
return self._layer_pass return self._layer_pass
def getCurrentLayer(self): def getCurrentLayer(self):
@ -310,7 +309,8 @@ class LayerView(View):
if event.type == Event.ViewActivateEvent: if event.type == Event.ViewActivateEvent:
# Make sure the LayerPass is created # Make sure the LayerPass is created
self.getLayerPass() layer_pass = self.getLayerPass()
self.getRenderer().addRenderPass(layer_pass)
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
self._onGlobalStackChanged() self._onGlobalStackChanged()
@ -335,6 +335,7 @@ class LayerView(View):
if self._global_container_stack: if self._global_container_stack:
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged) self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
self.getRenderer().removeRenderPass(self._layer_pass)
self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setLayerBindings(self._old_layer_bindings)
self._composite_pass.setCompositeShader(self._old_composite_shader) self._composite_pass.setCompositeShader(self._old_composite_shader)

View File

@ -103,6 +103,7 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
self._can_pause = True self._can_pause = True
self._can_abort = True self._can_abort = True
self._can_pre_heat_bed = False self._can_pre_heat_bed = False
self._can_control_manually = False
self._cluster_size = int(properties.get(b"cluster_size", 0)) self._cluster_size = int(properties.get(b"cluster_size", 0))
self._cleanupRequest() self._cleanupRequest()

View File

@ -102,6 +102,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._target_bed_temperature = 0 self._target_bed_temperature = 0
self._processing_preheat_requests = True self._processing_preheat_requests = True
self._can_control_manually = False
self.setPriority(3) # Make sure the output device gets selected above local file output self.setPriority(3) # Make sure the output device gets selected above local file output
self.setName(key) self.setName(key)
self.setShortDescription(i18n_catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print over network")) self.setShortDescription(i18n_catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print over network"))

View File

@ -56,7 +56,8 @@ class XRayView(View):
# Currently the RenderPass constructor requires a size > 0 # Currently the RenderPass constructor requires a size > 0
# This should be fixed in RenderPass's constructor. # This should be fixed in RenderPass's constructor.
self._xray_pass = XRayPass.XRayPass(1, 1) self._xray_pass = XRayPass.XRayPass(1, 1)
self.getRenderer().addRenderPass(self._xray_pass)
self.getRenderer().addRenderPass(self._xray_pass)
if not self._xray_composite_shader: if not self._xray_composite_shader:
self._xray_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray_composite.shader")) self._xray_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray_composite.shader"))
@ -74,5 +75,6 @@ class XRayView(View):
self._composite_pass.setCompositeShader(self._xray_composite_shader) self._composite_pass.setCompositeShader(self._xray_composite_shader)
if event.type == Event.ViewDeactivateEvent: if event.type == Event.ViewDeactivateEvent:
self.getRenderer().removeRenderPass(self._xray_pass)
self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setLayerBindings(self._old_layer_bindings)
self._composite_pass.setCompositeShader(self._old_composite_shader) self._composite_pass.setCompositeShader(self._old_composite_shader)

View File

@ -33,9 +33,10 @@ class XmlMaterialProfile(InstanceContainer):
# #
# \param xml_version: The version number found in an XML file. # \param xml_version: The version number found in an XML file.
# \return The corresponding setting_version. # \return The corresponding setting_version.
def xmlVersionToSettingVersion(self, xml_version: str) -> int: @classmethod
def xmlVersionToSettingVersion(cls, xml_version: str) -> int:
if xml_version == "1.3": if xml_version == "1.3":
return 4 return CuraApplication.SettingVersion
return 0 #Older than 1.3. return 0 #Older than 1.3.
def getInheritedFiles(self): def getInheritedFiles(self):
@ -407,15 +408,16 @@ class XmlMaterialProfile(InstanceContainer):
def getConfigurationTypeFromSerialized(self, serialized: str) -> Optional[str]: def getConfigurationTypeFromSerialized(self, serialized: str) -> Optional[str]:
return "materials" return "materials"
def getVersionFromSerialized(self, serialized: str) -> Optional[int]: @classmethod
def getVersionFromSerialized(cls, serialized: str) -> Optional[int]:
data = ET.fromstring(serialized) data = ET.fromstring(serialized)
version = 1 version = XmlMaterialProfile.Version
# get setting version # get setting version
if "version" in data.attrib: if "version" in data.attrib:
setting_version = self.xmlVersionToSettingVersion(data.attrib["version"]) setting_version = XmlMaterialProfile.xmlVersionToSettingVersion(data.attrib["version"])
else: else:
setting_version = self.xmlVersionToSettingVersion("1.2") setting_version = XmlMaterialProfile.xmlVersionToSettingVersion("1.2")
return version * 1000000 + setting_version return version * 1000000 + setting_version

View File

@ -5,24 +5,16 @@ import xml.etree.ElementTree as ET
from UM.VersionUpgrade import VersionUpgrade from UM.VersionUpgrade import VersionUpgrade
from cura.CuraApplication import CuraApplication
from .XmlMaterialProfile import XmlMaterialProfile
class XmlMaterialUpgrader(VersionUpgrade): class XmlMaterialUpgrader(VersionUpgrade):
def getXmlVersion(self, serialized): def getXmlVersion(self, serialized):
data = ET.fromstring(serialized) return XmlMaterialProfile.getVersionFromSerialized(serialized)
version = 1
# get setting version
if "version" in data.attrib:
setting_version = self._xmlVersionToSettingVersion(data.attrib["version"])
else:
setting_version = self._xmlVersionToSettingVersion("1.2")
return version * 1000000 + setting_version
def _xmlVersionToSettingVersion(self, xml_version: str) -> int: def _xmlVersionToSettingVersion(self, xml_version: str) -> int:
if xml_version == "1.3": return XmlMaterialProfile.xmlVersionToSettingVersion(xml_version)
return 2
return 0 #Older than 1.3.
def upgradeMaterial(self, serialised, filename): def upgradeMaterial(self, serialised, filename):
data = ET.fromstring(serialised) data = ET.fromstring(serialised)

View File

@ -19,7 +19,7 @@ def getMetaData():
"mimetype": "application/x-ultimaker-material-profile" "mimetype": "application/x-ultimaker-material-profile"
}, },
"version_upgrade": { "version_upgrade": {
("materials", 1000000): ("materials", 1000003, upgrader.upgradeMaterial), ("materials", 1000000): ("materials", 1000004, upgrader.upgradeMaterial),
}, },
"sources": { "sources": {
"materials": { "materials": {

View File

@ -3974,16 +3974,6 @@
"limit_to_extruder": "support_infill_extruder_nr", "limit_to_extruder": "support_infill_extruder_nr",
"enabled": "support_enable and support_use_towers", "enabled": "support_enable and support_use_towers",
"settable_per_mesh": true "settable_per_mesh": true
},
"remove_empty_first_layers":
{
"label": "Remove Empty First Layers",
"description": "Remove empty layers beneath the first printed layer if they are present.",
"type": "bool",
"default_value": true,
"enabled": "not support_enable",
"settable_per_mesh": false,
"settable_per_extruder": false
} }
} }
}, },
@ -4894,6 +4884,16 @@
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false, "settable_per_extruder": false,
"settable_per_meshgroup": true "settable_per_meshgroup": true
},
"remove_empty_first_layers":
{
"label": "Remove Empty First Layers",
"description": "Remove empty layers beneath the first printed layer if they are present. Disabling this setting can cause empty first layers if the Slicing Tolerance setting is set to Exclusive or Middle.",
"type": "bool",
"default_value": true,
"enabled": "not support_enable",
"settable_per_mesh": false,
"settable_per_extruder": false
} }
} }
}, },

View File

@ -18,7 +18,6 @@ Item {
UM.I18nCatalog { id: catalog; name:"cura"} UM.I18nCatalog { id: catalog; name:"cura"}
height: childrenRect.height height: childrenRect.height
width: childrenRect.width
Connections Connections
{ {

View File

@ -677,6 +677,341 @@ Column
watchedProperties: ["value"] watchedProperties: ["value"]
} }
Column
{
visible: connectedPrinter != null ? connectedPrinter.canControlManually : false
enabled:
{
if (connectedPrinter == null)
{
return false; //Can't control the printer if not connected.
}
if (!connectedPrinter.acceptsCommands)
{
return false; //Not allowed to do anything.
}
if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline")
{
return false; //Printer is in a state where it can't react to manual control
}
return true;
}
Loader
{
sourceComponent: monitorSection
property string label: catalog.i18nc("@label", "Printer control")
}
Row
{
width: base.width - 2 * UM.Theme.getSize("default_margin").width
height: childrenRect.height + UM.Theme.getSize("default_margin").width
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").width
Label
{
text: catalog.i18nc("@label", "Jog Position")
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
width: Math.floor(parent.width * 0.4) - UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("setting_control").height
verticalAlignment: Text.AlignVCenter
}
GridLayout
{
columns: 3
rows: 4
rowSpacing: UM.Theme.getSize("default_lining").width
columnSpacing: UM.Theme.getSize("default_lining").height
Label
{
text: catalog.i18nc("@label", "X/Y")
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
width: height
height: UM.Theme.getSize("setting_control").height
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
Layout.row: 1
Layout.column: 2
Layout.preferredWidth: width
Layout.preferredHeight: height
}
Button
{
Layout.row: 2
Layout.column: 2
Layout.preferredWidth: width
Layout.preferredHeight: height
iconSource: UM.Theme.getIcon("arrow_top");
style: monitorButtonStyle
width: height
height: UM.Theme.getSize("setting_control").height
onClicked:
{
connectedPrinter.moveHead(0, distancesRow.currentDistance, 0)
}
}
Button
{
Layout.row: 3
Layout.column: 1
Layout.preferredWidth: width
Layout.preferredHeight: height
iconSource: UM.Theme.getIcon("arrow_left");
style: monitorButtonStyle
width: height
height: UM.Theme.getSize("setting_control").height
onClicked:
{
connectedPrinter.moveHead(-distancesRow.currentDistance, 0, 0)
}
}
Button
{
Layout.row: 3
Layout.column: 3
Layout.preferredWidth: width
Layout.preferredHeight: height
iconSource: UM.Theme.getIcon("arrow_right");
style: monitorButtonStyle
width: height
height: UM.Theme.getSize("setting_control").height
onClicked:
{
connectedPrinter.moveHead(distancesRow.currentDistance, 0, 0)
}
}
Button
{
Layout.row: 4
Layout.column: 2
Layout.preferredWidth: width
Layout.preferredHeight: height
iconSource: UM.Theme.getIcon("arrow_bottom");
style: monitorButtonStyle
width: height
height: UM.Theme.getSize("setting_control").height
onClicked:
{
connectedPrinter.moveHead(0, -distancesRow.currentDistance, 0)
}
}
Button
{
Layout.row: 3
Layout.column: 2
Layout.preferredWidth: width
Layout.preferredHeight: height
iconSource: UM.Theme.getIcon("home");
style: monitorButtonStyle
width: height
height: UM.Theme.getSize("setting_control").height
onClicked:
{
connectedPrinter.homeHead()
}
}
}
Column
{
spacing: UM.Theme.getSize("default_lining").height
Label
{
text: catalog.i18nc("@label", "Z")
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
width: UM.Theme.getSize("section").height
height: UM.Theme.getSize("setting_control").height
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
Button
{
iconSource: UM.Theme.getIcon("arrow_top");
style: monitorButtonStyle
width: height
height: UM.Theme.getSize("setting_control").height
onClicked:
{
connectedPrinter.moveHead(0, 0, distancesRow.currentDistance)
}
}
Button
{
iconSource: UM.Theme.getIcon("home");
style: monitorButtonStyle
width: height
height: UM.Theme.getSize("setting_control").height
onClicked:
{
connectedPrinter.homeBed()
}
}
Button
{
iconSource: UM.Theme.getIcon("arrow_bottom");
style: monitorButtonStyle
width: height
height: UM.Theme.getSize("setting_control").height
onClicked:
{
connectedPrinter.moveHead(0, 0, -distancesRow.currentDistance)
}
}
}
}
Row
{
id: distancesRow
width: base.width - 2 * UM.Theme.getSize("default_margin").width
height: childrenRect.height + UM.Theme.getSize("default_margin").width
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").width
property real currentDistance: 10
Label
{
text: catalog.i18nc("@label", "Jog Distance")
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
width: Math.floor(parent.width * 0.4) - UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("setting_control").height
verticalAlignment: Text.AlignVCenter
}
Row
{
Repeater
{
model: distancesModel
delegate: Button
{
height: UM.Theme.getSize("setting_control").height
width: height + UM.Theme.getSize("default_margin").width
text: model.label
exclusiveGroup: distanceGroup
checkable: true
checked: distancesRow.currentDistance == model.value
onClicked: distancesRow.currentDistance = model.value
style: ButtonStyle {
background: Rectangle {
border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width
border.color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_border");
}
else if (control.checked || control.pressed)
{
return UM.Theme.getColor("action_button_active_border");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered_border");
}
return UM.Theme.getColor("action_button_border");
}
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled");
}
else if (control.checked || control.pressed)
{
return UM.Theme.getColor("action_button_active");
}
else if (control.hovered)
{
return UM.Theme.getColor("action_button_hovered");
}
return UM.Theme.getColor("action_button");
}
Behavior on color { ColorAnimation { duration: 50; } }
Label {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: UM.Theme.getSize("default_lining").width * 2
anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_text");
}
else if (control.checked || control.pressed)
{
return UM.Theme.getColor("action_button_active_text");
}
else if (control.hovered)
{
return UM.Theme.getColor("action_button_hovered_text");
}
return UM.Theme.getColor("action_button_text");
}
font: UM.Theme.getFont("default")
text: control.text
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideMiddle
}
}
label: Item { }
}
}
}
}
}
ListModel
{
id: distancesModel
ListElement { label: "0.1"; value: 0.1 }
ListElement { label: "1"; value: 1 }
ListElement { label: "10"; value: 10 }
ListElement { label: "100"; value: 100 }
}
ExclusiveGroup { id: distanceGroup }
}
Loader Loader
{ {
sourceComponent: monitorSection sourceComponent: monitorSection
@ -754,4 +1089,86 @@ Column
} }
} }
} }
Component
{
id: monitorButtonStyle
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");
}
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");
}
return UM.Theme.getColor("action_button");
}
Behavior on color
{
ColorAnimation
{
duration: 50
}
}
}
label: Item
{
UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width: Math.floor(control.width / 2)
height: Math.floor(control.height / 2)
sourceSize.width: width
sourceSize.height: width
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");
}
return UM.Theme.getColor("action_button_text");
}
source: control.iconSource
}
}
}
}
} }

View File

@ -18,6 +18,8 @@ Item {
property var backend: CuraApplication.getBackend(); property var backend: CuraApplication.getBackend();
property bool activity: CuraApplication.platformActivity; property bool activity: CuraApplication.platformActivity;
property alias buttonRowWidth: saveRow.width
property string fileBaseName property string fileBaseName
property string statusText: property string statusText:
{ {
@ -89,17 +91,30 @@ Item {
Item { Item {
id: saveRow id: saveRow
width: base.width 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("sidebar_margin").width);
}
height: saveToButton.height height: saveToButton.height
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height
anchors.left: parent.left anchors.right: parent.right
clip: true
Row { Row {
id: additionalComponentsRow id: additionalComponentsRow
anchors.top: parent.top anchors.top: parent.top
anchors.right: saveToButton.visible ? saveToButton.left : parent.right anchors.right: saveToButton.visible ? saveToButton.left : parent.right
anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width anchors.rightMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width
} }

View File

@ -30,6 +30,7 @@ Rectangle
property variant printMaterialLengths: PrintInformation.materialLengths property variant printMaterialLengths: PrintInformation.materialLengths
property variant printMaterialWeights: PrintInformation.materialWeights property variant printMaterialWeights: PrintInformation.materialWeights
property variant printMaterialCosts: PrintInformation.materialCosts property variant printMaterialCosts: PrintInformation.materialCosts
property variant printMaterialNames: PrintInformation.materialNames
color: UM.Theme.getColor("sidebar") color: UM.Theme.getColor("sidebar")
UM.I18nCatalog { id: catalog; name:"cura"} UM.I18nCatalog { id: catalog; name:"cura"}
@ -313,31 +314,32 @@ Rectangle
anchors.bottomMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize) anchors.bottomMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize)
} }
Rectangle Item
{ {
id: printSpecs id: printSpecs
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width
anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height
height: timeDetails.height + timeSpecDescription.height + lengthSpec.height height: timeDetails.height + costSpec.height
width: base.width - (saveButton.buttonRowWidth + UM.Theme.getSize("sidebar_margin").width)
visible: !monitoringPrint visible: !monitoringPrint
clip: true
Label Label
{ {
id: timeDetails id: timeDetails
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: timeSpecDescription.top anchors.bottom: costSpec.top
font: UM.Theme.getFont("large") font: UM.Theme.getFont("large")
color: UM.Theme.getColor("text_subtext") color: UM.Theme.getColor("text_subtext")
text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label Hours and minutes", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short) text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label Hours and minutes", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short)
MouseArea MouseArea
{ {
id: infillMouseArea id: timeDetailsMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
//enabled: base.settingsEnabled
onEntered: onEntered:
{ {
@ -345,19 +347,35 @@ Rectangle
if(base.printDuration.valid && !base.printDuration.isTotalDurationZero) if(base.printDuration.valid && !base.printDuration.isTotalDurationZero)
{ {
// All the time information for the different features is achieved // All the time information for the different features is achieved
var print_time = PrintInformation.getFeaturePrintTimes() var print_time = PrintInformation.getFeaturePrintTimes();
var total_seconds = parseInt(base.printDuration.getDisplayString(UM.DurationFormat.Seconds))
// A message is created and displayed when the user hover the time label // A message is created and displayed when the user hover the time label
var content = catalog.i18nc("@tooltip", "<b>Time information</b>") var content = catalog.i18nc("@tooltip", "<b>Time specification</b><br/><table>");
for(var feature in print_time) for(var feature in print_time)
{ {
if(!print_time[feature].isTotalDurationZero) if(!print_time[feature].isTotalDurationZero)
{ {
content += "<br /><i>" + feature + "</i>: " + print_time[feature].getDisplayString(UM.DurationFormat.Short) var feature_name = "";
if (feature.length <= 11)
{
feature_name = feature
}
else{
feature_name = feature.substring(0, 8) + "..."
}
content += "<tr><td>" + feature_name + ":" +
"&nbsp;&nbsp;</td><td>" + print_time[feature].getDisplayString(UM.DurationFormat.Short) +
"&nbsp;&nbsp;</td><td>" + Math.round(100 * parseInt(print_time[feature].getDisplayString(UM.DurationFormat.Seconds)) / total_seconds) + "%" +
"</td></tr>";
} }
} }
content += "</table>";
base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), content) base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), content);
} }
} }
onExited: onExited:
@ -369,20 +387,84 @@ Rectangle
Label Label
{ {
id: timeSpecDescription
anchors.left: parent.left function getSpecsData(){
anchors.bottom: lengthSpec.top
font: UM.Theme.getFont("very_small") var lengths = [];
color: UM.Theme.getColor("text_subtext") var total_length = 0;
text: catalog.i18nc("@description", "Print time") var weights = [];
} var total_weight = 0;
Label var costs = [];
{ var total_cost = 0;
id: lengthSpec var some_costs_known = false;
var names = [];
if(base.printMaterialLengths) {
for(var index = 0; index < base.printMaterialLengths.length; index++)
{
if(base.printMaterialLengths[index] > 0)
{
names.push(base.printMaterialNames[index]);
lengths.push(base.printMaterialLengths[index].toFixed(2));
weights.push(String(Math.floor(base.printMaterialWeights[index])));
var cost = base.printMaterialCosts[index] == undefined ? 0 : base.printMaterialCosts[index].toFixed(2);
costs.push(cost);
if(cost > 0)
{
some_costs_known = true;
}
total_length += base.printMaterialLengths[index];
total_weight += base.printMaterialWeights[index];
total_cost += base.printMaterialCosts[index];
}
}
}
if(lengths.length == 0)
{
lengths = ["0.00"];
weights = ["0"];
costs = ["0.00"];
}
var tooltip_html = "<b>%1</b><br/><table>".arg(catalog.i18nc("@label", "Cost specification"));
for(var index = 0; index < lengths.length; index++)
{
var item_strings = [
"%1:".arg(names[index]),
catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]),
catalog.i18nc("@label g for grams", "%1g").arg(weights[index]),
"%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]),
];
tooltip_html += "<tr>";
for(var item = 0; item < item_strings.length; item++) {
tooltip_html += "<td>%1&nbsp;&nbsp;</td>".arg(item_strings[item]);
}
}
var item_strings = [
catalog.i18nc("@label", "Total:"),
catalog.i18nc("@label m for meter", "%1m").arg(total_length.toFixed(2)),
catalog.i18nc("@label g for grams", "%1g").arg(Math.round(total_weight)),
"%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(total_cost.toFixed(2)),
];
tooltip_html += "<tr>";
for(var item = 0; item < item_strings.length; item++) {
tooltip_html += "<td>%1&nbsp;&nbsp;</td>".arg(item_strings[item]);
}
tooltip_html += "</tr></table>";
tooltipText = tooltip_html;
return tooltipText
}
id: costSpec
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
font: UM.Theme.getFont("very_small") font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text_subtext") color: UM.Theme.getColor("text_subtext")
elide: Text.ElideMiddle
width: parent.width
property string tooltipText
text: text:
{ {
var lengths = []; var lengths = [];
@ -421,6 +503,27 @@ Rectangle
return catalog.i18nc("@label Print estimates: m for meters, g for grams", "%1m / ~ %2g").arg(lengths.join(" + ")).arg(weights.join(" + ")); return catalog.i18nc("@label Print estimates: m for meters, g for grams", "%1m / ~ %2g").arg(lengths.join(" + ")).arg(weights.join(" + "));
} }
} }
MouseArea
{
id: costSpecMouseArea
anchors.fill: parent
hoverEnabled: true
onEntered:
{
if(base.printDuration.valid && !base.printDuration.isTotalDurationZero)
{
var show_data = costSpec.getSpecsData()
base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), show_data);
}
}
onExited:
{
base.hideTooltip();
}
}
} }
} }

View File

@ -54,6 +54,7 @@ UM.PointingRectangle {
rightMargin: UM.Theme.getSize("tooltip_margins").width; rightMargin: UM.Theme.getSize("tooltip_margins").width;
} }
wrapMode: Text.Wrap; wrapMode: Text.Wrap;
textFormat: Text.RichText
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
color: UM.Theme.getColor("tooltip_text"); color: UM.Theme.getColor("tooltip_text");
} }

View File

@ -30,9 +30,11 @@ Rectangle
Component.onCompleted: { Component.onCompleted: {
startMonitoringPrint.connect(function () { startMonitoringPrint.connect(function () {
base.monitoringPrint = true base.monitoringPrint = true
UM.Controller.disableModelRendering()
}) })
stopMonitoringPrint.connect(function () { stopMonitoringPrint.connect(function () {
base.monitoringPrint = false base.monitoringPrint = false
UM.Controller.enableModelRendering()
}) })
} }

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
<path d="m 8.5727081,5.62578 v 2.97725 q 0,0.16127 -0.1178498,0.27912 Q 8.3370085,9 8.1757405,9 H 5.7939349 V 6.61819 H 4.2060646 V 9 H 1.824259 Q 1.6629909,9 1.5451412,8.88215 1.4272914,8.7643 1.4272914,8.60303 V 5.62578 q 0,-0.006 0.0031,-0.0186 0.0031,-0.0124 0.0031,-0.0186 L 4.9999998,2.64852 8.5665054,5.58856 q 0.0062,0.0124 0.0062,0.0372 z M 9.955892,5.19779 9.5713297,5.65679 q -0.049621,0.0558 -0.130255,0.0682 h -0.018608 q -0.080634,0 -0.130255,-0.0434 L 4.9999998,2.10269 0.70778771,5.6816 Q 0.63335631,5.7312 0.55892486,5.725 0.47829087,5.7126 0.42866987,5.6568 L 0.04410752,5.1978 Q -0.00551343,5.1358 6.8917799e-4,5.05204 0.00689178,4.96834 0.06891799,4.91869 L 4.5286008,1.20331 q 0.1984838,-0.16127 0.471399,-0.16127 0.2729153,0 0.471399,0.16127 L 6.9848377,2.46864 V 1.25913 q 0,-0.0868 0.055824,-0.14266 0.055824,-0.0558 0.1426602,-0.0558 h 1.1909028 q 0.086837,0 0.1426602,0.0558 0.055824,0.0558 0.055824,0.14266 V 3.7898 l 1.3583734,1.12888 q 0.062026,0.0496 0.068229,0.13335 0.0062,0.0837 -0.043418,0.14576 z" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB