diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py
index 511b66c46b..72cad13468 100644
--- a/cura/BuildVolume.py
+++ b/cura/BuildVolume.py
@@ -452,7 +452,10 @@ class BuildVolume(SceneNode):
if not used_extruders:
# If no extruder is used, assume that the active extruder is used (else nothing is drawn)
- used_extruders = [extruder_manager.getActiveExtruderStack()]
+ if extruder_manager.getActiveExtruderStack():
+ used_extruders = [extruder_manager.getActiveExtruderStack()]
+ else:
+ used_extruders = [self._global_container_stack]
result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) #Normal machine disallowed areas can always be added.
prime_areas = self._computeDisallowedAreasPrime(disallowed_border_size, used_extruders)
diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py
index 6ed7759c34..4753955337 100644
--- a/cura/CuraApplication.py
+++ b/cura/CuraApplication.py
@@ -129,6 +129,7 @@ class CuraApplication(QtApplication):
{
("quality", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"),
("machine_stack", UM.Settings.ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"),
+ ("extruder_train", UM.Settings.ContainerStack.Version): (self.ResourceTypes.ExtruderStack, "application/x-uranium-extruderstack"),
("preferences", UM.Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"),
("user", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer")
}
diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py
index 7e06b95100..af3cb62406 100644
--- a/cura/Settings/ExtrudersModel.py
+++ b/cura/Settings/ExtrudersModel.py
@@ -140,8 +140,6 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
for extruder in manager.getMachineExtruders(global_container_stack.getId()):
extruder_name = extruder.getName()
material = extruder.findContainer({ "type": "material" })
- if material and not self._simple_names:
- extruder_name = "%s (%s)" % (material.getName(), extruder_name)
position = extruder.getMetaDataEntry("position", default = "0") # Get the position
try:
position = int(position)
diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py
index f7d2cc01f1..397a63c194 100644
--- a/plugins/3MFReader/ThreeMFReader.py
+++ b/plugins/3MFReader/ThreeMFReader.py
@@ -187,10 +187,12 @@ class ThreeMFReader(MeshReader):
build_item_node = self._createNodeFromObject(object, self._base_name + "_" + str(id))
# compensate for original center position, if object(s) is/are not around its zero position
- extents = build_item_node.getMeshData().getExtents()
- center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
transform_matrix = Matrix()
- transform_matrix.setByTranslation(center_vector)
+ mesh_data = build_item_node.getMeshData()
+ if mesh_data is not None:
+ extents = mesh_data.getExtents()
+ center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
+ transform_matrix.setByTranslation(center_vector)
# offset with transform from 3mf
transform = build_item.get("transform")
diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py
index d50fe8c571..46806cf54d 100644
--- a/plugins/3MFReader/ThreeMFWorkspaceReader.py
+++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py
@@ -349,7 +349,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
global_stack = stack
Job.yieldThread()
except:
- Logger.log("W", "We failed to serialize the stack. Trying to clean up.")
+ Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")
# Something went really wrong. Try to remove any data that we added.
for container in containers_to_add:
self._container_registry.getInstance().removeContainer(container.getId())
@@ -447,9 +447,17 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
def _getContainerIdListFromSerialized(self, serialized):
parser = configparser.ConfigParser(interpolation=None, empty_lines_in_values=False)
parser.read_string(serialized)
- container_string = parser["general"].get("containers", "")
- container_list = container_string.split(",")
- return [container_id for container_id in container_list if container_id != ""]
+
+ container_ids = []
+ if "containers" in parser:
+ for index, container_id in parser.items("containers"):
+ container_ids.append(container_id)
+ elif parser.has_option("general", "containers"):
+ container_string = parser["general"].get("containers", "")
+ container_list = container_string.split(",")
+ container_ids = [container_id for container_id in container_list if container_id != ""]
+
+ return container_ids
def _getMachineNameFromSerializedStack(self, serialized):
parser = configparser.ConfigParser(interpolation=None, empty_lines_in_values=False)
@@ -461,4 +469,5 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
metadata = data.iterfind("./um:metadata/um:name/um:label", {"um": "http://www.ultimaker.com/material"})
for entry in metadata:
return entry.text
- pass
\ No newline at end of file
+ pass
+
diff --git a/plugins/RemovableDriveOutputDevice/OSXRemovableDrivePlugin.py b/plugins/RemovableDriveOutputDevice/OSXRemovableDrivePlugin.py
index c96bf8bacf..6d8b5021ae 100644
--- a/plugins/RemovableDriveOutputDevice/OSXRemovableDrivePlugin.py
+++ b/plugins/RemovableDriveOutputDevice/OSXRemovableDrivePlugin.py
@@ -17,41 +17,60 @@ class OSXRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
drives = {}
p = subprocess.Popen(["system_profiler", "SPUSBDataType", "-xml"], stdout = subprocess.PIPE)
plist = plistlib.loads(p.communicate()[0])
- p.wait()
- for entry in plist:
- if "_items" in entry:
- for item in entry["_items"]:
- for dev in item["_items"]:
- if "removable_media" in dev and dev["removable_media"] == "yes" and "volumes" in dev and len(dev["volumes"]) > 0:
- for vol in dev["volumes"]:
- if "mount_point" in vol:
- volume = vol["mount_point"]
- drives[volume] = os.path.basename(volume)
+ result = self._recursiveSearch(plist, "removable_media")
p = subprocess.Popen(["system_profiler", "SPCardReaderDataType", "-xml"], stdout=subprocess.PIPE)
plist = plistlib.loads(p.communicate()[0])
- p.wait()
- for entry in plist:
- if "_items" in entry:
- for item in entry["_items"]:
- for dev in item["_items"]:
- if "removable_media" in dev and dev["removable_media"] == "yes" and "volumes" in dev and len(dev["volumes"]) > 0:
- for vol in dev["volumes"]:
- if "mount_point" in vol:
- volume = vol["mount_point"]
- drives[volume] = os.path.basename(volume)
+ result.extend(self._recursiveSearch(plist, "removable_media"))
+
+ for drive in result:
+ # Ignore everything not explicitly marked as removable
+ if drive["removable_media"] != "yes":
+ continue
+
+ # Ignore any removable device that does not have an actual volume
+ if "volumes" not in drive or not drive["volumes"]:
+ continue
+
+ for volume in drive["volumes"]:
+ if not "mount_point" in volume:
+ continue
+
+ mount_point = volume["mount_point"]
+
+ if "_name" in volume:
+ drive_name = volume["_name"]
+ else:
+ drive_name = os.path.basename(mount_point)
+
+ drives[mount_point] = drive_name
return drives
def performEjectDevice(self, device):
p = subprocess.Popen(["diskutil", "eject", device.getId()], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
output = p.communicate()
- Logger.log("d", "umount returned: %s.", repr(output))
return_code = p.wait()
if return_code != 0:
return False
else:
- return True
\ No newline at end of file
+ return True
+
+ # Recursively search for key in a plist parsed by plistlib
+ def _recursiveSearch(self, plist, key):
+ result = []
+ for entry in plist:
+ if key in entry:
+ result.append(entry)
+ continue
+
+ if "_items" in entry:
+ result.extend(self._recursiveSearch(entry["_items"], key))
+
+ if "Media" in entry:
+ result.extend(self._recursiveSearch(entry["Media"], key))
+
+ return result
diff --git a/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py b/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py
new file mode 100644
index 0000000000..dce2b311bb
--- /dev/null
+++ b/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py
@@ -0,0 +1,120 @@
+# Copyright (c) 2016 Ultimaker B.V.
+# Cura is released under the terms of the AGPLv3 or higher.
+
+import configparser #To get version numbers from config files.
+import os
+import os.path
+import io
+
+from UM import Resources
+from UM.VersionUpgrade import VersionUpgrade # Superclass of the plugin.
+
+class VersionUpgrade22to24(VersionUpgrade):
+
+ def upgradeMachineInstance(self, serialised, filename):
+ # All of this is needed to upgrade custom variant machines from old Cura to 2.4 where
+ # `definition_changes` instance container has been introduced. Variant files which
+ # look like the the handy work of the old machine settings plugin are converted directly
+ # on disk.
+
+ config = configparser.ConfigParser(interpolation = None)
+ config.read_string(serialised) # Read the input string as config file.
+ config.set("general", "version", "3")
+
+ container_list = []
+ if config.has_section("containers"):
+ for index, container_id in config.items("containers"):
+ container_list.append(container_id)
+ elif config.has_option("general", "containers"):
+ containers = config.get("general", "containers")
+ container_list = containers.split(",")
+
+ user_variants = self.__getUserVariants()
+ name_path_dict = {}
+ for variant in user_variants:
+ name_path_dict[variant.get("name")] = variant.get("path")
+
+ user_variant_names = set(container_list).intersection(name_path_dict.keys())
+ if len(user_variant_names):
+ # One of the user defined variants appears in the list of containers in the stack.
+
+ for variant_name in user_variant_names: # really there should just be one variant to convert.
+ config_name = self.__convertVariant(name_path_dict.get(variant_name))
+
+ # Change the name of variant and insert empty_variant into the stack.
+ new_container_list = []
+ for item in container_list:
+ if item == variant_name:
+ new_container_list.append(config_name)
+ new_container_list.append("empty_variant")
+ else:
+ new_container_list.append(item)
+
+ container_list = new_container_list
+
+ if not config.has_section("containers"):
+ config.add_section("containers")
+
+ config.remove_option("general", "containers")
+
+ for index in range(len(container_list)):
+ config.set("containers", index, container_list[index])
+
+ output = io.StringIO()
+ config.write(output)
+ return [filename], [output.getvalue()]
+
+ def __convertVariant(self, variant_path):
+ # Copy the variant to the machine_instances/*_settings.inst.cfg
+ variant_config = configparser.ConfigParser(interpolation=None)
+ with open(variant_path, "r") as fhandle:
+ variant_config.read_file(fhandle)
+
+ if variant_config.has_section("general") and variant_config.has_option("general", "name"):
+ config_name = variant_config.get("general", "name")
+ if config_name.endswith("_variant"):
+ config_name = config_name[:-len("_variant")] + "_settings"
+ variant_config.set("general", "name", config_name)
+
+ if not variant_config.has_section("metadata"):
+ variant_config.add_section("metadata")
+ variant_config.set("metadata", "type", "definition_changes")
+
+ resource_path = Resources.getDataStoragePath()
+ machine_instances_dir = os.path.join(resource_path, "machine_instances")
+
+ if variant_path.endswith("_variant.inst.cfg"):
+ variant_path = variant_path[:-len("_variant.inst.cfg")] + "_settings.inst.cfg"
+
+ with open(os.path.join(machine_instances_dir, os.path.basename(variant_path)), "w") as fp:
+ variant_config.write(fp)
+
+ return config_name
+
+ def __getUserVariants(self):
+ resource_path = Resources.getDataStoragePath()
+ variants_dir = os.path.join(resource_path, "variants")
+
+ result = []
+ for entry in os.scandir(variants_dir):
+ if entry.name.endswith('.inst.cfg') and entry.is_file():
+ config = configparser.ConfigParser(interpolation = None)
+ with open(entry.path, "r") as fhandle:
+ config.read_file(fhandle)
+ if config.has_section("general") and config.has_option("general", "name"):
+ result.append( { "path": entry.path, "name": config.get("general", "name") } )
+ return result
+
+ def upgradeExtruderTrain(self, serialised, filename):
+ config = configparser.ConfigParser(interpolation = None)
+ config.read_string(serialised) # Read the input string as config file.
+ config.set("general", "version", "3") # Just bump the version number. That is all we need for now.
+
+ output = io.StringIO()
+ config.write(output)
+ return [filename], [output.getvalue()]
+
+ def getCfgVersion(self, serialised):
+ parser = configparser.ConfigParser(interpolation = None)
+ parser.read_string(serialised)
+ return int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
diff --git a/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py b/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py
new file mode 100644
index 0000000000..85d53199e4
--- /dev/null
+++ b/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py
@@ -0,0 +1,38 @@
+# Copyright (c) 2016 Ultimaker B.V.
+# Cura is released under the terms of the AGPLv3 or higher.
+
+from . import VersionUpgrade
+
+from UM.i18n import i18nCatalog
+catalog = i18nCatalog("cura")
+
+upgrade = VersionUpgrade.VersionUpgrade22to24()
+
+def getMetaData():
+ return {
+ "plugin": {
+ "name": catalog.i18nc("@label", "Version Upgrade 2.2 to 2.4"),
+ "author": "Ultimaker",
+ "version": "1.0",
+ "description": catalog.i18nc("@info:whatsthis", "Upgrades configurations from Cura 2.2 to Cura 2.4."),
+ "api": 3
+ },
+ "version_upgrade": {
+ # From To Upgrade function
+ ("machine_instance", 2): ("machine_stack", 3, upgrade.upgradeMachineInstance),
+ ("extruder_train", 2): ("extruder_train", 3, upgrade.upgradeExtruderTrain)
+ },
+ "sources": {
+ "machine_stack": {
+ "get_version": upgrade.getCfgVersion,
+ "location": {"./machine_instances"}
+ },
+ "extruder_train": {
+ "get_version": upgrade.getCfgVersion,
+ "location": {"./extruders"}
+ },
+ }
+ }
+
+def register(app):
+ return { "version_upgrade": upgrade }
diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json
index 71bbcccbdd..5e492bf531 100644
--- a/resources/definitions/ultimaker3.def.json
+++ b/resources/definitions/ultimaker3.def.json
@@ -106,6 +106,8 @@
"line_width": { "value": "machine_nozzle_size * 0.875" },
"machine_min_cool_heat_time_window": { "value": "15" },
"default_material_print_temperature": { "value": "200" },
+ "material_bed_temperature": { "maximum_value": "115" },
+ "material_bed_temperature_layer_0": { "maximum_value": "115" },
"material_standby_temperature": { "value": "100" },
"multiple_mesh_overlap": { "value": "0" },
"prime_tower_enable": { "value": "True" },
diff --git a/resources/extruders/ultimaker3_extended_extruder_left.def.json b/resources/extruders/ultimaker3_extended_extruder_left.def.json
index 202272b096..3335e85ae3 100644
--- a/resources/extruders/ultimaker3_extended_extruder_left.def.json
+++ b/resources/extruders/ultimaker3_extended_extruder_left.def.json
@@ -1,7 +1,7 @@
{
"id": "ultimaker3_extended_extruder_left",
"version": 2,
- "name": "Print core 1",
+ "name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker3_extended",
diff --git a/resources/extruders/ultimaker3_extended_extruder_right.def.json b/resources/extruders/ultimaker3_extended_extruder_right.def.json
index 0f85b2dd09..2e072753b1 100644
--- a/resources/extruders/ultimaker3_extended_extruder_right.def.json
+++ b/resources/extruders/ultimaker3_extended_extruder_right.def.json
@@ -1,7 +1,7 @@
{
"id": "ultimaker3_extended_extruder_right",
"version": 2,
- "name": "Print core 2",
+ "name": "Extruder 2",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker3_extended",
diff --git a/resources/extruders/ultimaker3_extruder_left.def.json b/resources/extruders/ultimaker3_extruder_left.def.json
index 83efa25dbb..141fd2f80c 100644
--- a/resources/extruders/ultimaker3_extruder_left.def.json
+++ b/resources/extruders/ultimaker3_extruder_left.def.json
@@ -1,7 +1,7 @@
{
"id": "ultimaker3_extruder_left",
"version": 2,
- "name": "Print core 1",
+ "name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker3",
diff --git a/resources/extruders/ultimaker3_extruder_right.def.json b/resources/extruders/ultimaker3_extruder_right.def.json
index 4a75059c40..50a369e3ed 100644
--- a/resources/extruders/ultimaker3_extruder_right.def.json
+++ b/resources/extruders/ultimaker3_extruder_right.def.json
@@ -1,7 +1,7 @@
{
"id": "ultimaker3_extruder_right",
"version": 2,
- "name": "Print core 2",
+ "name": "Extruder 2",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker3",
diff --git a/resources/extruders/ultimaker_original_dual_1st.def.json b/resources/extruders/ultimaker_original_dual_1st.def.json
index 058dbf3028..62ec8479c9 100644
--- a/resources/extruders/ultimaker_original_dual_1st.def.json
+++ b/resources/extruders/ultimaker_original_dual_1st.def.json
@@ -1,7 +1,7 @@
{
"id": "ultimaker_original_dual_1st",
"version": 2,
- "name": "1st Extruder",
+ "name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker_original_dual",
diff --git a/resources/extruders/ultimaker_original_dual_2nd.def.json b/resources/extruders/ultimaker_original_dual_2nd.def.json
index 4b600d0281..42a4da524b 100644
--- a/resources/extruders/ultimaker_original_dual_2nd.def.json
+++ b/resources/extruders/ultimaker_original_dual_2nd.def.json
@@ -1,7 +1,7 @@
{
"id": "ultimaker_original_dual_2nd",
"version": 2,
- "name": "2nd Extruder",
+ "name": "Extruder 2",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker_original_dual",
diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml
index 83f980bf86..70e3780707 100644
--- a/resources/qml/Preferences/MaterialsPage.qml
+++ b/resources/qml/Preferences/MaterialsPage.qml
@@ -127,7 +127,7 @@ UM.ManagementPage
{
text: catalog.i18nc("@action:button", "Activate");
iconName: "list-activate";
- enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId
+ enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId && Cura.MachineManager.hasMaterials
onClicked: Cura.MachineManager.setActiveMaterial(base.currentItem.id)
},
Button
@@ -144,8 +144,10 @@ UM.ManagementPage
{
return
}
-
- Cura.MachineManager.setActiveMaterial(material_id)
+ if(Cura.MachineManager.hasMaterials)
+ {
+ Cura.MachineManager.setActiveMaterial(material_id)
+ }
}
},
Button
diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml
index 5f20f92b20..6af3985527 100644
--- a/resources/qml/Settings/SettingView.qml
+++ b/resources/qml/Settings/SettingView.qml
@@ -84,7 +84,7 @@ Item
onTextChanged:
{
- definitionsModel.filter = {"label": "*" + text};
+ definitionsModel.filter = {"i18n_label": "*" + text};
findingSettings = (text.length > 0);
if(findingSettings != lastFindingSettings)
{
diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml
index 77e82b5f92..f9c314d660 100644
--- a/resources/qml/Sidebar.qml
+++ b/resources/qml/Sidebar.qml
@@ -8,6 +8,7 @@ import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
+import "Menus"
Rectangle
{
@@ -30,9 +31,21 @@ Rectangle
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
- color: UM.Theme.getColor("sidebar");
+ color: UM.Theme.getColor("sidebar")
UM.I18nCatalog { id: catalog; name:"cura"}
+ Timer {
+ id: tooltipDelayTimer
+ interval: 500
+ repeat: false
+ property var item
+ property string text
+
+ onTriggered:
+ {
+ base.showTooltip(base, {x:1, y:item.y}, text);
+ }
+ }
function showTooltip(item, position, text)
{
@@ -73,7 +86,7 @@ Rectangle
}
}
- // Mode selection buttons for changing between Setting & Monitor print mode
+ // Printer selection and mode selection buttons for changing between Setting & Monitor print mode
Rectangle
{
id: sidebarHeaderBar
@@ -85,25 +98,90 @@ Rectangle
Row
{
anchors.left: parent.left
- anchors.leftMargin: UM.Theme.getSize("default_margin").width;
anchors.right: parent.right
+ anchors.rightMargin: UM.Theme.getSize("default_margin").width
+ spacing: UM.Theme.getSize("default_margin").width
+
+ ToolButton
+ {
+ id: machineSelection
+ text: Cura.MachineManager.activeMachineName
+
+ width: parent.width - (showSettings.width + showMonitor.width + 2 * UM.Theme.getSize("default_margin").width)
+ height: UM.Theme.getSize("sidebar_header").height
+ tooltip: Cura.MachineManager.activeMachineName
+
+ anchors.verticalCenter: parent.verticalCenter
+ style: ButtonStyle {
+ background: Rectangle {
+ color: control.hovered ? UM.Theme.getColor("button_hover") :
+ control.pressed ? UM.Theme.getColor("button_hover") : UM.Theme.getColor("sidebar_header_bar")
+ Behavior on color { ColorAnimation { duration: 50; } }
+
+ UM.RecolorImage {
+ id: downArrow
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: UM.Theme.getSize("default_margin").width
+ width: UM.Theme.getSize("standard_arrow").width
+ height: UM.Theme.getSize("standard_arrow").height
+ sourceSize.width: width
+ sourceSize.height: width
+ color: UM.Theme.getColor("text_reversed")
+ source: UM.Theme.getIcon("arrow_bottom")
+ }
+ Label {
+ id: sidebarComboBoxLabel
+ color: UM.Theme.getColor("text_reversed")
+ text: control.text;
+ elide: Text.ElideRight;
+ anchors.left: parent.left;
+ anchors.leftMargin: UM.Theme.getSize("default_margin").width
+ anchors.right: downArrow.left;
+ anchors.rightMargin: control.rightMargin;
+ anchors.verticalCenter: parent.verticalCenter;
+ font: UM.Theme.getFont("large")
+ }
+ }
+ label: Label{}
+ }
+
+ menu: PrinterMenu { }
+ }
+
Button
{
id: showSettings
- width: (parent.width - UM.Theme.getSize("default_margin").width) / 2
+ width: height
height: UM.Theme.getSize("sidebar_header").height
onClicked: monitoringPrint = false
iconSource: UM.Theme.getIcon("tab_settings");
checkable: true
checked: !monitoringPrint
exclusiveGroup: sidebarHeaderBarGroup
+ property string tooltipText: catalog.i18nc("@tooltip", "Print Setup
Edit or review the settings for the active print job.")
+
+ onHoveredChanged: {
+ if (hovered)
+ {
+ tooltipDelayTimer.item = showSettings
+ tooltipDelayTimer.text = tooltipText
+ tooltipDelayTimer.start();
+ }
+ else
+ {
+ tooltipDelayTimer.stop();
+ base.hideTooltip();
+ }
+ }
style: UM.Theme.styles.sidebar_header_tab
}
+
Button
{
id: showMonitor
- width: (parent.width - UM.Theme.getSize("default_margin").width) / 2
+ width: height
height: UM.Theme.getSize("sidebar_header").height
onClicked: monitoringPrint = true
iconSource: {
@@ -139,6 +217,21 @@ Rectangle
checkable: true
checked: monitoringPrint
exclusiveGroup: sidebarHeaderBarGroup
+ property string tooltipText: catalog.i18nc("@tooltip", "Print Monitor
Monitor the state of the connected printer and the print job in progress.")
+
+ onHoveredChanged: {
+ if (hovered)
+ {
+ tooltipDelayTimer.item = showMonitor
+ tooltipDelayTimer.text = tooltipText
+ tooltipDelayTimer.start();
+ }
+ else
+ {
+ tooltipDelayTimer.stop();
+ base.hideTooltip();
+ }
+ }
style: UM.Theme.styles.sidebar_header_tab
}
@@ -151,7 +244,6 @@ Rectangle
width: parent.width
anchors.top: sidebarHeaderBar.bottom
- anchors.topMargin: UM.Theme.getSize("default_margin").height
onShowTooltip: base.showTooltip(item, location, text)
onHideTooltip: base.hideTooltip()
@@ -160,10 +252,11 @@ Rectangle
Rectangle {
id: headerSeparator
width: parent.width
- height: UM.Theme.getSize("sidebar_lining").height
+ visible: !monitoringPrint
+ height: visible ? UM.Theme.getSize("sidebar_lining").height : 0
color: UM.Theme.getColor("sidebar_lining")
anchors.top: header.bottom
- anchors.topMargin: UM.Theme.getSize("default_margin").height
+ anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0
}
onCurrentModeIndexChanged:
@@ -212,6 +305,20 @@ Rectangle
checked: base.currentModeIndex == index
onClicked: base.currentModeIndex = index
+ onHoveredChanged: {
+ if (hovered)
+ {
+ tooltipDelayTimer.item = settingsModeSelection
+ tooltipDelayTimer.text = model.tooltipText
+ tooltipDelayTimer.start();
+ }
+ else
+ {
+ tooltipDelayTimer.stop();
+ base.hideTooltip();
+ }
+ }
+
style: ButtonStyle {
background: Rectangle {
border.width: UM.Theme.getSize("default_lining").width
@@ -408,8 +515,18 @@ Rectangle
Component.onCompleted:
{
- modesListModel.append({ text: catalog.i18nc("@title:tab", "Recommended"), item: sidebarSimple, showFilterButton: false })
- modesListModel.append({ text: catalog.i18nc("@title:tab", "Custom"), item: sidebarAdvanced, showFilterButton: true })
+ modesListModel.append({
+ text: catalog.i18nc("@title:tab", "Recommended"),
+ tooltipText: catalog.i18nc("@tooltip", "Recommended Print Setup
Print with the recommended settings for the selected printer, material and quality."),
+ item: sidebarSimple,
+ showFilterButton: false
+ })
+ modesListModel.append({
+ text: catalog.i18nc("@title:tab", "Custom"),
+ tooltipText: catalog.i18nc("@tooltip", "Custom Print Setup
Print with finegrained control over every last bit of the slicing process."),
+ item: sidebarAdvanced,
+ showFilterButton: true
+ })
sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "immediate": true });
var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml
index e894392b06..78bde0c437 100644
--- a/resources/qml/SidebarHeader.qml
+++ b/resources/qml/SidebarHeader.qml
@@ -21,145 +21,142 @@ Column
signal showTooltip(Item item, point location, string text)
signal hideTooltip()
- Row
+ Item
{
- id: machineSelectionRow
- height: UM.Theme.getSize("sidebar_setup").height
+ id: extruderSelectionRow
+ width: parent.width
+ height: UM.Theme.getSize("sidebar_tabs").height
+ visible: machineExtruderCount.properties.value > 1 && !sidebar.monitoringPrint
- anchors
+ Rectangle
{
- left: parent.left
- leftMargin: UM.Theme.getSize("default_margin").width
- right: parent.right
- rightMargin: UM.Theme.getSize("default_margin").width
+ id: extruderSeparator
+ visible: machineExtruderCount.properties.value > 1 && !sidebar.monitoringPrint
+
+ width: parent.width
+ height: parent.height
+ color: UM.Theme.getColor("sidebar_lining")
+
+ anchors.top: extruderSelectionRow.top
}
- Label
+ ListView
{
- id: machineSelectionLabel
- text: catalog.i18nc("@label:listbox", "Printer:");
- anchors.verticalCenter: parent.verticalCenter
- font: UM.Theme.getFont("default");
- color: UM.Theme.getColor("text");
+ id: extrudersList
+ property var index: 0
- width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
- }
+ height: UM.Theme.getSize("sidebar_header_mode_tabs").height
+ width: parent.width
+ boundsBehavior: Flickable.StopAtBounds
- ToolButton
- {
- id: machineSelection
- text: Cura.MachineManager.activeMachineName;
+ anchors
+ {
+ left: parent.left
+ right: parent.right
+ bottom: extruderSelectionRow.bottom
+ }
- height: UM.Theme.getSize("setting_control").height
- tooltip: Cura.MachineManager.activeMachineName
- anchors.verticalCenter: parent.verticalCenter
- style: UM.Theme.styles.sidebar_header_button
+ ExclusiveGroup { id: extruderMenuGroup; }
- width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width
+ orientation: ListView.Horizontal
- menu: PrinterMenu { }
+ model: Cura.ExtrudersModel { id: extrudersModel; addGlobal: false }
+
+ Connections
+ {
+ target: Cura.MachineManager
+ onGlobalContainerChanged:
+ {
+ forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values.
+ var extruder_index = (machineExtruderCount.properties.value == 1) ? -1 : 0
+ ExtruderManager.setActiveExtruderIndex(extruder_index);
+ }
+ }
+
+ delegate: Button
+ {
+ height: ListView.view.height
+ width: ListView.view.width / extrudersModel.rowCount()
+
+ text: model.name
+ tooltip: model.name
+ exclusiveGroup: extruderMenuGroup
+ checked: base.currentExtruderIndex == index
+
+ onClicked:
+ {
+ forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values.
+ ExtruderManager.setActiveExtruderIndex(index);
+ }
+
+ style: ButtonStyle
+ {
+ background: Rectangle
+ {
+ border.width: UM.Theme.getSize("default_lining").width
+ border.color: control.checked ? UM.Theme.getColor("tab_checked_border") :
+ control.pressed ? UM.Theme.getColor("tab_active_border") :
+ control.hovered ? UM.Theme.getColor("tab_hovered_border") : UM.Theme.getColor("tab_unchecked_border")
+ color: control.checked ? UM.Theme.getColor("tab_checked") :
+ control.pressed ? UM.Theme.getColor("tab_active") :
+ control.hovered ? UM.Theme.getColor("tab_hovered") : UM.Theme.getColor("tab_unchecked")
+ Behavior on color { ColorAnimation { duration: 50; } }
+
+ Rectangle
+ {
+ id: highlight
+ visible: control.checked
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ height: UM.Theme.getSize("sidebar_header_highlight").height
+ color: UM.Theme.getColor("sidebar_header_bar")
+ }
+
+ Rectangle
+ {
+ id: swatch
+ visible: index > -1
+ height: UM.Theme.getSize("setting_control").height / 2
+ width: height
+ anchors.left: parent.left
+ anchors.leftMargin: (parent.height - height) / 2
+ anchors.verticalCenter: parent.verticalCenter
+
+ color: model.color
+ border.width: UM.Theme.getSize("default_lining").width
+ border.color: UM.Theme.getColor("setting_control_border")
+ }
+
+ Label
+ {
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: swatch.visible ? swatch.right : parent.left
+ anchors.leftMargin: swatch.visible ? UM.Theme.getSize("default_margin").width / 2 : UM.Theme.getSize("default_margin").width
+ anchors.right: parent.right
+ anchors.rightMargin: UM.Theme.getSize("default_margin").width / 2
+
+ color: control.checked ? UM.Theme.getColor("tab_checked_text") :
+ control.pressed ? UM.Theme.getColor("tab_active_text") :
+ control.hovered ? UM.Theme.getColor("tab_hovered_text") : UM.Theme.getColor("tab_unchecked_text")
+
+ font: UM.Theme.getFont("default")
+ text: control.text
+ elide: Text.ElideRight
+ }
+ }
+ label: Item { }
+ }
+ }
}
}
- ListView
+ Item
{
- id: extrudersList
- property var index: 0
-
- visible: machineExtruderCount.properties.value > 1 && !sidebar.monitoringPrint
- height: UM.Theme.getSize("sidebar_header_mode_toggle").height
-
- boundsBehavior: Flickable.StopAtBounds
-
- anchors
- {
- left: parent.left
- leftMargin: UM.Theme.getSize("default_margin").width
- right: parent.right
- rightMargin: UM.Theme.getSize("default_margin").width
- }
-
- ExclusiveGroup { id: extruderMenuGroup; }
-
- orientation: ListView.Horizontal
-
- model: Cura.ExtrudersModel { id: extrudersModel; addGlobal: false }
-
- Connections
- {
- target: Cura.MachineManager
- onGlobalContainerChanged:
- {
- forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values.
- var extruder_index = (machineExtruderCount.properties.value == 1) ? -1 : 0
- ExtruderManager.setActiveExtruderIndex(extruder_index);
- }
- }
-
- delegate: Button
- {
- height: ListView.view.height
- width: ListView.view.width / extrudersModel.rowCount()
-
- text: model.name
- tooltip: model.name
- exclusiveGroup: extruderMenuGroup
- checked: base.currentExtruderIndex == index
-
- onClicked:
- {
- forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values.
- ExtruderManager.setActiveExtruderIndex(index);
- }
-
- style: ButtonStyle
- {
- background: Rectangle
- {
- border.width: UM.Theme.getSize("default_lining").width
- border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") :
- control.pressed ? UM.Theme.getColor("toggle_active_border") :
- control.hovered ? UM.Theme.getColor("toggle_hovered_border") : UM.Theme.getColor("toggle_unchecked_border")
- color: control.checked ? UM.Theme.getColor("toggle_checked") :
- control.pressed ? UM.Theme.getColor("toggle_active") :
- control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked")
- Behavior on color { ColorAnimation { duration: 50; } }
-
- Rectangle
- {
- id: swatch
- visible: index > -1
- height: UM.Theme.getSize("setting_control").height / 2
- width: height
- anchors.left: parent.left
- anchors.leftMargin: (parent.height - height) / 2
- anchors.verticalCenter: parent.verticalCenter
-
- color: model.color
- border.width: UM.Theme.getSize("default_lining").width
- border.color: UM.Theme.getColor("toggle_checked")
- }
-
- Label
- {
- anchors.verticalCenter: parent.verticalCenter
- anchors.left: swatch.visible ? swatch.right : parent.left
- anchors.leftMargin: swatch.visible ? UM.Theme.getSize("default_margin").width / 2 : UM.Theme.getSize("default_margin").width
- anchors.right: parent.right
- anchors.rightMargin: UM.Theme.getSize("default_margin").width / 2
-
- color: control.checked ? UM.Theme.getColor("toggle_checked_text") :
- control.pressed ? UM.Theme.getColor("toggle_active_text") :
- control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text")
-
- font: UM.Theme.getFont("default")
- text: control.text
- elide: Text.ElideRight
- }
- }
- label: Item { }
- }
- }
+ id: variantRowSpacer
+ height: UM.Theme.getSize("default_margin").height / 4
+ width: height
+ visible: !extruderSelectionRow.visible
}
Row
diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml
index c7da237648..499125a6f9 100644
--- a/resources/qml/SidebarSimple.qml
+++ b/resources/qml/SidebarSimple.qml
@@ -30,7 +30,7 @@ Item
id: infillCellLeft
anchors.top: parent.top
anchors.left: parent.left
- width: base.width / 100 * 35 - UM.Theme.getSize("default_margin").width
+ width: base.width * .45 - UM.Theme.getSize("default_margin").width
height: childrenRect.height
Label
@@ -52,7 +52,7 @@ Item
id: infillCellRight
height: childrenRect.height;
- width: base.width / 100 * 65
+ width: base.width * .55
spacing: UM.Theme.getSize("default_margin").width
anchors.left: infillCellLeft.right
@@ -231,7 +231,7 @@ Item
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: enableSupportCheckBox.verticalCenter
- width: parent.width / 100 * 45 - 3 * UM.Theme.getSize("default_margin").width
+ width: parent.width * .45 - 3 * UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@label", "Enable Support");
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
@@ -279,7 +279,7 @@ Item
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: supportExtruderCombobox.verticalCenter
- width: parent.width / 100 * 45 - 3 * UM.Theme.getSize("default_margin").width
+ width: parent.width * .45 - 3 * UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@label", "Support Extruder");
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
@@ -319,7 +319,7 @@ Item
}
anchors.left: supportExtruderLabel.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
- width: parent.width / 100 * 55
+ width: parent.width * .55
height:
{
if ((supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1))
@@ -332,6 +332,7 @@ Item
return 0;
}
}
+ Behavior on height { NumberAnimation { duration: 100 } }
style: UM.Theme.styles.combobox_color
enabled: base.settingsEnabled
@@ -377,7 +378,7 @@ Item
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: adhesionCheckBox.verticalCenter
- width: parent.width / 100 * 45 - 3 * UM.Theme.getSize("default_margin").width
+ width: parent.width * .45 - 3 * UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@label", "Build Plate Adhesion");
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
diff --git a/resources/qml/SidebarTooltip.qml b/resources/qml/SidebarTooltip.qml
index 5cb7ff1f0b..7344834c7e 100644
--- a/resources/qml/SidebarTooltip.qml
+++ b/resources/qml/SidebarTooltip.qml
@@ -29,6 +29,11 @@ UM.PointingRectangle {
} else {
x = position.x - base.width;
y = position.y - UM.Theme.getSize("tooltip_arrow_margins").height;
+ if(y < 0)
+ {
+ position.y += -y;
+ y = 0;
+ }
}
base.opacity = 1;
target = Qt.point(40 , position.y + UM.Theme.getSize("tooltip_arrow_margins").height / 2)
diff --git a/resources/themes/cura/theme.json b/resources/themes/cura/theme.json
index a29aefa143..d5a95a7104 100644
--- a/resources/themes/cura/theme.json
+++ b/resources/themes/cura/theme.json
@@ -91,7 +91,21 @@
"toggle_hovered_text": [24, 41, 77, 255],
"toggle_active": [32, 166, 219, 255],
"toggle_active_border": [32, 166, 219, 255],
- "toggle_active_text": [255, 255, 255, 255],
+ "toggle_active_text": [24, 41, 77, 255],
+
+ "tab_checked": [255, 255, 255, 255],
+ "tab_checked_border": [255, 255, 255, 255],
+ "tab_checked_text": [24, 41, 77, 255],
+ "tab_unchecked": [245, 245, 245, 255],
+ "tab_unchecked_border": [245, 245, 245, 255],
+ "tab_unchecked_text": [127, 127, 127, 255],
+ "tab_hovered": [245, 245, 245, 255],
+ "tab_hovered_border": [245, 245, 245, 255],
+ "tab_hovered_text": [32, 166, 219, 255],
+ "tab_active": [255, 255, 255, 255],
+ "tab_active_border": [255, 255, 255, 255],
+ "tab_active_text": [24, 41, 77, 255],
+ "tab_background": [245, 245, 245, 255],
"action_button": [255, 255, 255, 255],
"action_button_text": [24, 41, 77, 255],
@@ -191,10 +205,12 @@
"sidebar": [35.0, 10.0],
"sidebar_header": [0.0, 4.0],
- "sidebar_header_highlight": [0.5, 0.5],
+ "sidebar_header_highlight": [0.25, 0.25],
"sidebar_header_mode_toggle": [0.0, 2.0],
+ "sidebar_header_mode_tabs": [0.0, 3.0],
"sidebar_lining": [0.5, 0.5],
"sidebar_setup": [0.0, 2.0],
+ "sidebar_tabs": [0.0, 3.5],
"sidebar_inputfields": [0.0, 2.0],
"simple_mode_infill_caption": [0.0, 5.0],
"simple_mode_infill_height": [0.0, 8.0],