diff --git a/cura/QualityManager.py b/cura/QualityManager.py
index e92829e546..813d23ea13 100644
--- a/cura/QualityManager.py
+++ b/cura/QualityManager.py
@@ -82,6 +82,17 @@ class QualityManager:
return list(common_quality_types)
+ def findAllQualitiesForMachineAndMaterials(self, machine_definition: "DefinitionContainerInterface", material_containers: List[InstanceContainer]) -> List[InstanceContainer]:
+ # Determine the common set of quality types which can be
+ # applied to all of the materials for this machine.
+ quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_containers[0])
+ qualities = set(quality_type_dict.values())
+ for material_container in material_containers[1:]:
+ next_quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_container)
+ qualities.update(set(next_quality_type_dict.values()))
+
+ return list(qualities)
+
## Fetches a dict of quality types names to quality profiles for a combination of machine and material.
#
# \param machine_definition \type{DefinitionContainer} the machine definition.
@@ -121,7 +132,7 @@ class QualityManager:
# \param material_container \type{InstanceContainer} the material.
# \return \type{List[InstanceContainer]} the list of suitable qualities.
def findAllQualitiesForMachineMaterial(self, machine_definition: "DefinitionContainerInterface", material_container: InstanceContainer) -> List[InstanceContainer]:
- criteria = {"type": "quality" }
+ criteria = {"type": "quality"}
result = self._getFilteredContainersForStack(machine_definition, [material_container], **criteria)
if not result:
basic_materials = self._getBasicMaterials(material_container)
diff --git a/cura/Settings/ProfilesModel.py b/cura/Settings/ProfilesModel.py
index 545f44401a..2942577fc6 100644
--- a/cura/Settings/ProfilesModel.py
+++ b/cura/Settings/ProfilesModel.py
@@ -1,6 +1,8 @@
-# Copyright (c) 2016 Ultimaker B.V.
+# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
+from collections import OrderedDict
+
from PyQt5.QtCore import Qt
from UM.Application import Application
@@ -10,14 +12,19 @@ from UM.Settings.Models.InstanceContainersModel import InstanceContainersModel
from cura.QualityManager import QualityManager
from cura.Settings.ExtruderManager import ExtruderManager
+
## QML Model for listing the current list of valid quality profiles.
#
class ProfilesModel(InstanceContainersModel):
LayerHeightRole = Qt.UserRole + 1001
+ LayerHeightWithoutUnitRole = Qt.UserRole + 1002
+ AvailableRole = Qt.UserRole + 1003
def __init__(self, parent = None):
super().__init__(parent)
self.addRoleName(self.LayerHeightRole, "layer_height")
+ self.addRoleName(self.LayerHeightWithoutUnitRole, "layer_height_without_unit")
+ self.addRoleName(self.AvailableRole, "available")
Application.getInstance().globalContainerStackChanged.connect(self._update)
@@ -47,8 +54,9 @@ class ProfilesModel(InstanceContainersModel):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack is None:
return []
+ global_stack_definition = global_container_stack.getBottom()
- # Get the list of extruders and place the selected extruder at the front of the list.
+ # Get the list of extruders and place the selected extruder at the front of the list.
extruder_manager = ExtruderManager.getInstance()
active_extruder = extruder_manager.getActiveExtruderStack()
extruder_stacks = extruder_manager.getActiveExtruderStacks()
@@ -56,10 +64,22 @@ class ProfilesModel(InstanceContainersModel):
extruder_stacks.remove(active_extruder)
extruder_stacks = [active_extruder] + extruder_stacks
- # Fetch the list of useable qualities across all extruders.
+ if ExtruderManager.getInstance().getActiveExtruderStacks():
+ # Multi-extruder machine detected.
+ materials = [extruder.material for extruder in extruder_stacks]
+ else:
+ # Machine with one extruder.
+ materials = [global_container_stack.material]
+
+ # Fetch the list of usable qualities across all extruders.
# The actual list of quality profiles come from the first extruder in the extruder list.
- return QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_container_stack,
- extruder_stacks)
+ result = QualityManager.getInstance().findAllQualitiesForMachineAndMaterials(global_stack_definition,
+ materials)
+ for quality in QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(
+ global_container_stack, extruder_stacks):
+ if quality not in result:
+ result.append(quality)
+ return result
## Re-computes the items in this model, and adds the layer height role.
def _recomputeItems(self):
@@ -67,6 +87,17 @@ class ProfilesModel(InstanceContainersModel):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack is None:
return
+
+ # Get the list of extruders and place the selected extruder at the front of the list.
+ extruder_manager = ExtruderManager.getInstance()
+ active_extruder = extruder_manager.getActiveExtruderStack()
+ extruder_stacks = extruder_manager.getActiveExtruderStacks()
+ if active_extruder in extruder_stacks:
+ extruder_stacks.remove(active_extruder)
+ extruder_stacks = [active_extruder] + extruder_stacks
+ # Get a list of available qualities for this machine and material
+ qualities = QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_container_stack,
+ extruder_stacks)
container_registry = ContainerRegistry.getInstance()
machine_manager = Application.getInstance().getMachineManager()
@@ -74,17 +105,44 @@ class ProfilesModel(InstanceContainersModel):
if not unit:
unit = ""
+ # group all quality items according to quality_types, so we know which profile suits the currently
+ # active machine and material, and later yield the right ones.
+ tmp_all_quality_items = OrderedDict()
for item in super()._recomputeItems():
+ profile = container_registry.findContainers(id = item["id"])
+ quality_type = profile[0].getMetaDataEntry("quality_type") if profile else ""
+
+ if quality_type not in tmp_all_quality_items:
+ tmp_all_quality_items[quality_type] = {"suitable_container": None,
+ "all_containers": []}
+
+ tmp_all_quality_items[quality_type]["all_containers"].append(item)
+ if tmp_all_quality_items[quality_type]["suitable_container"] is None and profile[0] in qualities:
+ tmp_all_quality_items[quality_type]["suitable_container"] = item
+
+ # reverse the ordering (finest first, coarsest last)
+ all_quality_items = OrderedDict()
+ for key in reversed(tmp_all_quality_items.keys()):
+ all_quality_items[key] = tmp_all_quality_items[key]
+
+ for data_item in all_quality_items.values():
+ item = data_item["suitable_container"]
+ if item is None:
+ item = data_item["all_containers"][0]
+
profile = container_registry.findContainers(id = item["id"])
if not profile:
item["layer_height"] = "" #Can't update a profile that is unknown.
+ item["available"] = False
yield item
continue
- #Easy case: This profile defines its own layer height.
profile = profile[0]
+ item["available"] = profile in qualities
+
+ #Easy case: This profile defines its own layer height.
if profile.hasProperty("layer_height", "value"):
- item["layer_height"] = str(profile.getProperty("layer_height", "value")) + unit
+ self._setItemLayerHeight(item, profile.getProperty("layer_height", "value"), unit)
yield item
continue
@@ -102,7 +160,7 @@ class ProfilesModel(InstanceContainersModel):
else:
quality = None
if quality and quality.hasProperty("layer_height", "value"):
- item["layer_height"] = str(quality.getProperty("layer_height", "value")) + unit
+ self._setItemLayerHeight(item, quality.getProperty("layer_height", "value"), unit)
yield item
continue
@@ -112,5 +170,9 @@ class ProfilesModel(InstanceContainersModel):
skip_until_container = global_container_stack.variant
if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No variant in stack.
skip_until_container = global_container_stack.getBottom()
- item["layer_height"] = str(global_container_stack.getRawProperty("layer_height", "value", skip_until_container = skip_until_container.getId())) + unit #Fall through to the currently loaded material.
+ self._setItemLayerHeight(item, global_container_stack.getRawProperty("layer_height", "value", skip_until_container = skip_until_container.getId()), unit) # Fall through to the currently loaded material.
yield item
+
+ def _setItemLayerHeight(self, item, value, unit):
+ item["layer_height"] = str(value) + unit
+ item["layer_height_without_unit"] = str(value)
diff --git a/resources/qml/Menus/ProfileMenu.qml b/resources/qml/Menus/ProfileMenu.qml
index 4a2908277e..d6412c50be 100644
--- a/resources/qml/Menus/ProfileMenu.qml
+++ b/resources/qml/Menus/ProfileMenu.qml
@@ -22,6 +22,7 @@ Menu
checked: Cura.MachineManager.activeQualityChangesId == "" && Cura.MachineManager.activeQualityType == model.metadata.quality_type
exclusiveGroup: group
onTriggered: Cura.MachineManager.setActiveQuality(model.id)
+ visible: model.available
}
onObjectAdded: menu.insertItem(index, object);
diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml
index b6b79ed3d4..8dd8670f05 100644
--- a/resources/qml/Settings/SettingView.qml
+++ b/resources/qml/Settings/SettingView.qml
@@ -9,6 +9,8 @@ import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
+import "../Menus"
+
Item
{
id: base;
@@ -18,6 +20,88 @@ Item
signal showTooltip(Item item, point location, string text);
signal hideTooltip();
+ Item
+ {
+ id: globalProfileRow
+ height: UM.Theme.getSize("sidebar_setup").height
+ visible: !sidebar.monitoringPrint && !sidebar.hideSettings
+
+ anchors
+ {
+ top: parent.top
+ left: parent.left
+ leftMargin: UM.Theme.getSize("sidebar_margin").width
+ right: parent.right
+ rightMargin: UM.Theme.getSize("sidebar_margin").width
+ }
+
+ Text
+ {
+ id: globalProfileLabel
+ text: catalog.i18nc("@label","Profile:");
+ width: parent.width * 0.45 - UM.Theme.getSize("sidebar_margin").width - 2
+ font: UM.Theme.getFont("default");
+ color: UM.Theme.getColor("text");
+ verticalAlignment: Text.AlignVCenter
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ }
+
+ ToolButton
+ {
+ id: globalProfileSelection
+
+ text: {
+ var result = Cura.MachineManager.activeQualityName;
+ if (Cura.MachineManager.activeQualityLayerHeight > 0) {
+ result += " ";
+ result += " - ";
+ result += Cura.MachineManager.activeQualityLayerHeight + "mm";
+ result += "";
+ }
+ return result;
+ }
+ enabled: !header.currentExtruderVisible || header.currentExtruderIndex > -1
+
+ width: parent.width * 0.55
+ height: UM.Theme.getSize("setting_control").height
+ anchors.left: globalProfileLabel.right
+ anchors.right: parent.right
+ tooltip: Cura.MachineManager.activeQualityName
+ style: UM.Theme.styles.sidebar_header_button
+ activeFocusOnPress: true;
+ menu: ProfileMenu { }
+
+ UM.SimpleButton
+ {
+ id: customisedSettings
+
+ visible: Cura.MachineManager.hasUserSettings
+ height: parent.height * 0.6
+ width: parent.height * 0.6
+
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width - UM.Theme.getSize("sidebar_margin").width
+
+ color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button");
+ iconSource: UM.Theme.getIcon("star");
+
+ onClicked:
+ {
+ forceActiveFocus();
+ Cura.Actions.manageProfiles.trigger()
+ }
+ onEntered:
+ {
+ var content = catalog.i18nc("@tooltip","Some setting/override values are different from the values stored in the profile.\n\nClick to open the profile manager.")
+ base.showTooltip(globalProfileRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), content)
+ }
+ onExited: base.hideTooltip()
+ }
+ }
+ }
+
Rectangle
{
id: filterContainer
@@ -40,7 +124,8 @@ Item
anchors
{
- top: parent.top
+ top: globalProfileRow.bottom
+ topMargin: UM.Theme.getSize("sidebar_margin").height
left: parent.left
leftMargin: UM.Theme.getSize("sidebar_margin").width
right: parent.right
diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml
index c598af7d99..ccaff1cd9a 100755
--- a/resources/qml/Sidebar.qml
+++ b/resources/qml/Sidebar.qml
@@ -212,95 +212,12 @@ Rectangle
}
}
- Item
- {
- id: globalProfileRow
- height: UM.Theme.getSize("sidebar_setup").height
- visible: !sidebar.monitoringPrint && !sidebar.hideSettings
-
- anchors
- {
- top: settingsModeSelection.bottom
- topMargin: UM.Theme.getSize("sidebar_margin").height
- left: parent.left
- leftMargin: UM.Theme.getSize("sidebar_margin").width
- right: parent.right
- rightMargin: UM.Theme.getSize("sidebar_margin").width
- }
-
- Text
- {
- id: globalProfileLabel
- text: catalog.i18nc("@label","Profile:");
- width: parent.width * 0.45 - UM.Theme.getSize("sidebar_margin").width - 2
- font: UM.Theme.getFont("default");
- color: UM.Theme.getColor("text");
- verticalAlignment: Text.AlignVCenter
- anchors.top: parent.top
- anchors.bottom: parent.bottom
- }
-
- ToolButton
- {
- id: globalProfileSelection
-
- text: {
- var result = Cura.MachineManager.activeQualityName;
- if (Cura.MachineManager.activeQualityLayerHeight > 0) {
- result += " ";
- result += " - ";
- result += Cura.MachineManager.activeQualityLayerHeight + "mm";
- result += "";
- }
- return result;
- }
- enabled: !header.currentExtruderVisible || header.currentExtruderIndex > -1
-
- width: parent.width * 0.55
- height: UM.Theme.getSize("setting_control").height
- anchors.left: globalProfileLabel.right
- anchors.right: parent.right
- tooltip: Cura.MachineManager.activeQualityName
- style: UM.Theme.styles.sidebar_header_button
- activeFocusOnPress: true;
- menu: ProfileMenu { }
-
- UM.SimpleButton
- {
- id: customisedSettings
-
- visible: Cura.MachineManager.hasUserSettings
- height: parent.height * 0.6
- width: parent.height * 0.6
-
- anchors.verticalCenter: parent.verticalCenter
- anchors.right: parent.right
- anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width - UM.Theme.getSize("sidebar_margin").width
-
- color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button");
- iconSource: UM.Theme.getIcon("star");
-
- onClicked:
- {
- forceActiveFocus();
- Cura.Actions.manageProfiles.trigger()
- }
- onEntered:
- {
- var content = catalog.i18nc("@tooltip","Some setting/override values are different from the values stored in the profile.\n\nClick to open the profile manager.")
- base.showTooltip(globalProfileRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), content)
- }
- onExited: base.hideTooltip()
- }
- }
- }
-
StackView
{
id: sidebarContents
anchors.bottom: footerSeparator.top
- anchors.top: globalProfileRow.bottom
+ anchors.top: settingsModeSelection.bottom
anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
anchors.left: base.left
anchors.right: base.right
diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml
index ffb5e1f00b..276eacef29 100644
--- a/resources/qml/SidebarSimple.qml
+++ b/resources/qml/SidebarSimple.qml
@@ -37,12 +37,385 @@ Item
height: childrenRect.height
color: UM.Theme.getColor("sidebar")
+ //
+ // Quality profile
+ //
+ Text
+ {
+ id: resolutionLabel
+ anchors.top: resolutionSlider.top
+ anchors.topMargin: UM.Theme.getSize("default_margin").height / 4
+ anchors.left: parent.left
+ anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width
+ width: UM.Theme.getSize("sidebar").width * .45 - UM.Theme.getSize("sidebar_margin").width
+
+ text: catalog.i18nc("@label", "Layer Height")
+ font: UM.Theme.getFont("default")
+ color: UM.Theme.getColor("text")
+ }
+
+ Text
+ {
+ id: speedLabel
+ anchors.bottom: resolutionSlider.bottom
+ anchors.left: parent.left
+ anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width
+
+ text: catalog.i18nc("@label", "Print Speed")
+ font: UM.Theme.getFont("default")
+ color: UM.Theme.getColor("text")
+ }
+
+ Text
+ {
+ id: speedLabelSlower
+ anchors.top: speedLabel.top
+ anchors.left: resolutionSlider.left
+
+ text: catalog.i18nc("@label", "Slower")
+ font: UM.Theme.getFont("default")
+ color: UM.Theme.getColor("text")
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ Text
+ {
+ id: speedLabelFaster
+ anchors.top: speedLabel.top
+ anchors.right: resolutionSlider.right
+
+ text: catalog.i18nc("@label", "Faster")
+ font: UM.Theme.getFont("default")
+ color: UM.Theme.getColor("text")
+ horizontalAlignment: Text.AlignRight
+ }
+
+ Item
+ {
+ id: resolutionSlider
+ anchors.top: parent.top
+ anchors.topMargin: UM.Theme.getSize("default_margin").height / 2
+ anchors.left: infillCellRight.left
+ anchors.right: infillCellRight.right
+ width: UM.Theme.getSize("sidebar").width * .55
+ height: UM.Theme.getSize("quality_slider_bar").height * 30
+
+ property var model: Cura.ProfilesModel
+
+ Connections
+ {
+ target: Cura.ProfilesModel
+ onItemsChanged:
+ {
+ resolutionSlider.updateCurrentQualityIndex();
+ resolutionSlider.updateBar();
+ }
+ }
+
+ Connections
+ {
+ target: Cura.MachineManager
+ onActiveQualityChanged:
+ {
+ resolutionSlider.updateCurrentQualityIndex();
+ resolutionSlider.updateBar();
+ }
+ }
+
+ Component.onCompleted:
+ {
+ updateCurrentQualityIndex();
+ updateBar();
+ }
+
+ function updateCurrentQualityIndex()
+ {
+ for (var i = 0; i < resolutionSlider.model.rowCount(); ++i)
+ {
+ if (Cura.MachineManager.activeQualityId == resolutionSlider.model.getItem(i).id)
+ {
+ if (resolutionSlider.currentQualityIndex != i)
+ {
+ resolutionSlider.currentQualityIndex = i;
+ }
+ return;
+ }
+ }
+ resolutionSlider.currentQualityIndex = undefined;
+ }
+
+ function updateBar()
+ {
+ fullRangeMax = Cura.ProfilesModel.rowCount();
+
+ // set avaiableMin
+ var foundAvaiableMin = false;
+ for (var i = 0; i < Cura.ProfilesModel.rowCount(); ++i)
+ {
+ if (Cura.ProfilesModel.getItem(i).available)
+ {
+ avaiableMin = i;
+ foundAvaiableMin = true;
+ break;
+ }
+ }
+ if (!foundAvaiableMin)
+ {
+ avaiableMin = undefined;
+ }
+
+ var foundAvaiableMax = false;
+ for (var i = Cura.ProfilesModel.rowCount() - 1; i >= 0; --i)
+ {
+ if (Cura.ProfilesModel.getItem(i).available)
+ {
+ avaiableMax = i;
+ foundAvaiableMax = true;
+ break;
+ }
+ }
+ if (!foundAvaiableMax)
+ {
+ avaiableMax = undefined;
+ }
+
+ currentHover = undefined;
+ backgroundBar.requestPaint();
+ }
+
+ property var fullRangeMin: 0
+ property var fullRangeMax: model.rowCount()
+
+ property var avaiableMin
+ property var avaiableMax
+ property var currentQualityIndex
+ property var currentHover
+
+ //TODO: get from theme
+ property var barLeftRightMargin: 5
+ property var tickLeftRightMargin: 2
+ property var tickMargin: 15
+ property var tickThickness: 1
+ property var tickWidth: 1
+ property var tickHeight: 5
+ property var tickTextHeight: 8
+ property var totalTickCount: fullRangeMax - fullRangeMin
+ property var selectedCircleDiameter: 10
+
+ property var showQualityText: false
+
+ property var tickStepSize: (width - (barLeftRightMargin + tickLeftRightMargin) * 2) / (totalTickCount > 1 ? totalTickCount - 1 : 1)
+ property var tickAreaList:
+ {
+ var area_list = [];
+ if (avaiableMin != undefined && avaiableMax != undefined)
+ {
+ for (var i = avaiableMin; i <= avaiableMax; ++i)
+ {
+ var start_x = (barLeftRightMargin + tickLeftRightMargin) + tickStepSize * (i - fullRangeMin);
+ var diameter = tickStepSize * 0.9;
+ start_x = start_x + tickWidth / 2 - (diameter / 2);
+ var end_x = start_x + diameter;
+ var start_y = height / 2 - diameter / 2;
+ var end_y = start_y + diameter;
+
+ var area = {"id": i,
+ "start_x": start_x, "end_x": end_x,
+ "start_y": start_y, "end_y": end_y,
+ };
+ area_list.push(area);
+ }
+ }
+ return area_list;
+ }
+
+ onCurrentHoverChanged:
+ {
+ backgroundBar.requestPaint();
+ }
+ onCurrentQualityIndex:
+ {
+ backgroundBar.requestPaint();
+ }
+
+ // background bar
+ Canvas
+ {
+ id: backgroundBar
+ anchors.fill: parent
+
+ Timer {
+ interval: 16
+ running: true
+ repeat: true
+ onTriggered: backgroundBar.requestPaint()
+ }
+
+ onPaint:
+ {
+ var ctx = getContext("2d");
+ ctx.reset();
+ ctx.fillStyle = UM.Theme.getColor("quality_slider_unavailable");
+
+ const bar_left_right_margin = resolutionSlider.barLeftRightMargin;
+ const tick_left_right_margin = resolutionSlider.tickLeftRightMargin;
+ const tick_margin = resolutionSlider.tickMargin;
+ const bar_thickness = resolutionSlider.tickThickness;
+ const tick_width = resolutionSlider.tickWidth;
+ const tick_height = resolutionSlider.tickHeight;
+ const tick_text_height = resolutionSlider.tickTextHeight;
+ const selected_circle_diameter = resolutionSlider.selectedCircleDiameter;
+
+ // draw unavailable bar
+ const bar_top = parent.height / 2 - bar_thickness / 2;
+ ctx.fillRect(bar_left_right_margin, bar_top, width - bar_left_right_margin * 2, bar_thickness);
+
+ // draw unavailable ticks
+ var total_tick_count = resolutionSlider.totalTickCount;
+ const step_size = resolutionSlider.tickStepSize;
+ var current_start_x = bar_left_right_margin + tick_left_right_margin;
+
+ const tick_top = parent.height / 2 - tick_height / 2;
+
+ for (var i = 0; i < total_tick_count; ++i)
+ {
+ ctx.fillRect(current_start_x, tick_top, tick_width, tick_height);
+ current_start_x += step_size;
+ }
+
+ // draw available bar and ticks
+ if (resolutionSlider.avaiableMin != undefined && resolutionSlider.avaiableMax != undefined)
+ {
+ current_start_x = (bar_left_right_margin + tick_left_right_margin) + step_size * (resolutionSlider.avaiableMin - resolutionSlider.fullRangeMin);
+ ctx.fillStyle = UM.Theme.getColor("quality_slider_available");
+ total_tick_count = resolutionSlider.avaiableMax - resolutionSlider.avaiableMin + 1;
+
+ const available_bar_width = step_size * (total_tick_count - 1);
+ ctx.fillRect(current_start_x, bar_top, available_bar_width, bar_thickness);
+
+ for (var i = 0; i < total_tick_count; ++i)
+ {
+ ctx.fillRect(current_start_x, tick_top, tick_width, tick_height);
+ current_start_x += step_size;
+ }
+ }
+
+ // print the selected circle
+ if (resolutionSlider.currentQualityIndex != undefined)
+ {
+ var circle_start_x = (bar_left_right_margin + tick_left_right_margin) + step_size * (resolutionSlider.currentQualityIndex - resolutionSlider.fullRangeMin);
+ circle_start_x = circle_start_x + tick_width / 2 - selected_circle_diameter / 2;
+ var circle_start_y = height / 2 - selected_circle_diameter / 2;
+ ctx.fillStyle = UM.Theme.getColor("quality_slider_handle");
+ ctx.beginPath();
+ ctx.ellipse(circle_start_x, circle_start_y, selected_circle_diameter, selected_circle_diameter);
+ ctx.fill();
+ ctx.closePath();
+ }
+
+ // print the hovered circle
+ if (resolutionSlider.currentHover != undefined && resolutionSlider.currentHover != resolutionSlider.currentQualityIndex)
+ {
+ var circle_start_x = (bar_left_right_margin + tick_left_right_margin) + step_size * (resolutionSlider.currentHover - resolutionSlider.fullRangeMin);
+ circle_start_x = circle_start_x + tick_width / 2 - selected_circle_diameter / 2;
+ var circle_start_y = height / 2 - selected_circle_diameter / 2;
+ ctx.fillStyle = UM.Theme.getColor("quality_slider_handle_hover");
+ ctx.beginPath();
+ ctx.ellipse(circle_start_x, circle_start_y, selected_circle_diameter, selected_circle_diameter);
+ ctx.fill();
+ ctx.closePath();
+ }
+
+ // print layer height texts
+ total_tick_count = resolutionSlider.totalTickCount;
+ const step_size = resolutionSlider.tickStepSize;
+ current_start_x = bar_left_right_margin + tick_left_right_margin;
+ for (var i = 0; i < total_tick_count; ++i)
+ {
+ const text_top = parent.height / 2 - tick_height - tick_text_height;
+ ctx.fillStyle = UM.Theme.getColor("quality_slider_text");
+
+ ctx.font = "12px sans-serif";
+ const string_length = resolutionSlider.model.getItem(i).layer_height_without_unit.length;
+ const offset = string_length / 2 * 4;
+
+ var start_x = current_start_x - offset;
+ if (i == 0)
+ {
+ start_x = 0;
+ }
+ else if (i == total_tick_count - 1)
+ {
+ start_x = current_start_x - offset * 2;
+ }
+
+ ctx.fillText(resolutionSlider.model.getItem(i).layer_height_without_unit, start_x, text_top);
+ current_start_x += step_size;
+ }
+
+ // print currently selected quality text
+ if (resolutionSlider.showQualityText && resolutionSlider.currentQualityIndex != undefine)
+ {
+ const text_top = parent.height / 2 + tick_height + tick_text_height * 2;
+ total_tick_count = resolutionSlider.totalTickCount;
+ const step_size = resolutionSlider.tickStepSize;
+ current_start_x = (tick_left_right_margin) + step_size * (resolutionSlider.currentQualityIndex - resolutionSlider.fullRangeMin);
+ ctx.fillStyle = UM.Theme.getColor("quality_slider_text");
+ ctx.fillText(resolutionSlider.model.getItem(resolutionSlider.currentQualityIndex).name, current_start_x - 6, text_top);
+ }
+ }
+
+ MouseArea
+ {
+ anchors.fill: parent
+ hoverEnabled: true
+
+ onClicked:
+ {
+ for (var i = 0; i < resolutionSlider.tickAreaList.length; ++i)
+ {
+ var area = resolutionSlider.tickAreaList[i];
+ if (area.start_x <= mouseX && mouseX <= area.end_x && area.start_y <= mouseY && mouseY <= area.end_y)
+ {
+ resolutionSlider.currentHover = undefined;
+ resolutionSlider.currentQualityIndex = area.id;
+
+ Cura.MachineManager.setActiveQuality(resolutionSlider.model.getItem(resolutionSlider.currentQualityIndex).id);
+ return;
+ }
+ }
+ resolutionSlider.currentHover = undefined;
+ }
+ onPositionChanged:
+ {
+ for (var i = 0; i < resolutionSlider.tickAreaList.length; ++i)
+ {
+ var area = resolutionSlider.tickAreaList[i];
+ if (area.start_x <= mouseX && mouseX <= area.end_x && area.start_y <= mouseY && mouseY <= area.end_y)
+ {
+ resolutionSlider.currentHover = area.id;
+ return;
+ }
+ }
+ resolutionSlider.currentHover = undefined;
+ }
+ onExited:
+ {
+ resolutionSlider.currentHover = undefined;
+ }
+ }
+ }
+ }
+
+ //
+ // Infill
+ //
Item
{
id: infillCellLeft
- anchors.top: parent.top
+ anchors.top: speedLabel.top
+ anchors.topMargin: UM.Theme.getSize("sidebar_margin").height * 1.2
anchors.left: parent.left
- anchors.topMargin: UM.Theme.getSize("sidebar_margin").height * 0.8
width: UM.Theme.getSize("sidebar").width * .45 - UM.Theme.getSize("sidebar_margin").width
height: childrenRect.height
@@ -71,6 +444,7 @@ Item
anchors.left: infillCellLeft.right
anchors.top: infillCellLeft.top
+ anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
Repeater
{
diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json
index 586db9761f..906a5c280e 100644
--- a/resources/themes/cura-dark/theme.json
+++ b/resources/themes/cura-dark/theme.json
@@ -192,6 +192,12 @@
"topbar_button_text_inactive": [255, 255, 255, 255],
"topbar_button_text_active": [255, 255, 255, 255],
"topbar_button_text_hovered": [255, 255, 255, 255],
- "topbar_background_color_monitoring": [39, 44, 48, 255]
+ "topbar_background_color_monitoring": [39, 44, 48, 255],
+
+ "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]
}
}
diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json
index 6fd8f43b3e..1271dfbe71 100644
--- a/resources/themes/cura-light/theme.json
+++ b/resources/themes/cura-light/theme.json
@@ -196,6 +196,12 @@
"slider_handle_border": [39, 44, 48, 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],
"checkbox_border": [64, 69, 72, 255],
@@ -338,6 +344,8 @@
"scrollbar": [0.75, 0.5],
+ "quality_slider_bar": [1, 0.2],
+
"slider_groove": [0.3, 0.3],
"slider_handle": [1.0, 1.0],
"slider_layerview_size": [1.0, 22.0],