Merge pull request #2423 from Ultimaker/feature_slider_for_quality

CURA-4182 Slider for quality profile
This commit is contained in:
ChrisTerBeke 2017-09-14 11:09:38 +02:00 committed by GitHub
commit 6f512e9f97
8 changed files with 562 additions and 98 deletions

View File

@ -82,6 +82,17 @@ class QualityManager:
return list(common_quality_types) 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. ## 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. # \param machine_definition \type{DefinitionContainer} the machine definition.
@ -121,7 +132,7 @@ class QualityManager:
# \param material_container \type{InstanceContainer} the material. # \param material_container \type{InstanceContainer} the material.
# \return \type{List[InstanceContainer]} the list of suitable qualities. # \return \type{List[InstanceContainer]} the list of suitable qualities.
def findAllQualitiesForMachineMaterial(self, machine_definition: "DefinitionContainerInterface", material_container: InstanceContainer) -> List[InstanceContainer]: 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) result = self._getFilteredContainersForStack(machine_definition, [material_container], **criteria)
if not result: if not result:
basic_materials = self._getBasicMaterials(material_container) basic_materials = self._getBasicMaterials(material_container)

View File

@ -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. # Cura is released under the terms of the AGPLv3 or higher.
from collections import OrderedDict
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from UM.Application import Application from UM.Application import Application
@ -10,14 +12,19 @@ from UM.Settings.Models.InstanceContainersModel import InstanceContainersModel
from cura.QualityManager import QualityManager from cura.QualityManager import QualityManager
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
## QML Model for listing the current list of valid quality profiles. ## QML Model for listing the current list of valid quality profiles.
# #
class ProfilesModel(InstanceContainersModel): class ProfilesModel(InstanceContainersModel):
LayerHeightRole = Qt.UserRole + 1001 LayerHeightRole = Qt.UserRole + 1001
LayerHeightWithoutUnitRole = Qt.UserRole + 1002
AvailableRole = Qt.UserRole + 1003
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
self.addRoleName(self.LayerHeightRole, "layer_height") 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) Application.getInstance().globalContainerStackChanged.connect(self._update)
@ -47,8 +54,9 @@ class ProfilesModel(InstanceContainersModel):
global_container_stack = Application.getInstance().getGlobalContainerStack() global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack is None: if global_container_stack is None:
return [] 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() extruder_manager = ExtruderManager.getInstance()
active_extruder = extruder_manager.getActiveExtruderStack() active_extruder = extruder_manager.getActiveExtruderStack()
extruder_stacks = extruder_manager.getActiveExtruderStacks() extruder_stacks = extruder_manager.getActiveExtruderStacks()
@ -56,10 +64,22 @@ class ProfilesModel(InstanceContainersModel):
extruder_stacks.remove(active_extruder) extruder_stacks.remove(active_extruder)
extruder_stacks = [active_extruder] + extruder_stacks 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. # The actual list of quality profiles come from the first extruder in the extruder list.
return QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_container_stack, result = QualityManager.getInstance().findAllQualitiesForMachineAndMaterials(global_stack_definition,
extruder_stacks) 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. ## Re-computes the items in this model, and adds the layer height role.
def _recomputeItems(self): def _recomputeItems(self):
@ -67,6 +87,17 @@ class ProfilesModel(InstanceContainersModel):
global_container_stack = Application.getInstance().getGlobalContainerStack() global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack is None: if global_container_stack is None:
return 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() container_registry = ContainerRegistry.getInstance()
machine_manager = Application.getInstance().getMachineManager() machine_manager = Application.getInstance().getMachineManager()
@ -74,17 +105,44 @@ class ProfilesModel(InstanceContainersModel):
if not unit: if not unit:
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(): 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"]) profile = container_registry.findContainers(id = item["id"])
if not profile: if not profile:
item["layer_height"] = "" #Can't update a profile that is unknown. item["layer_height"] = "" #Can't update a profile that is unknown.
item["available"] = False
yield item yield item
continue continue
#Easy case: This profile defines its own layer height.
profile = profile[0] profile = profile[0]
item["available"] = profile in qualities
#Easy case: This profile defines its own layer height.
if profile.hasProperty("layer_height", "value"): 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 yield item
continue continue
@ -102,7 +160,7 @@ class ProfilesModel(InstanceContainersModel):
else: else:
quality = None quality = None
if quality and quality.hasProperty("layer_height", "value"): 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 yield item
continue continue
@ -112,5 +170,9 @@ class ProfilesModel(InstanceContainersModel):
skip_until_container = global_container_stack.variant skip_until_container = global_container_stack.variant
if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No variant in stack. if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No variant in stack.
skip_until_container = global_container_stack.getBottom() 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 yield item
def _setItemLayerHeight(self, item, value, unit):
item["layer_height"] = str(value) + unit
item["layer_height_without_unit"] = str(value)

View File

@ -22,6 +22,7 @@ Menu
checked: Cura.MachineManager.activeQualityChangesId == "" && Cura.MachineManager.activeQualityType == model.metadata.quality_type checked: Cura.MachineManager.activeQualityChangesId == "" && Cura.MachineManager.activeQualityType == model.metadata.quality_type
exclusiveGroup: group exclusiveGroup: group
onTriggered: Cura.MachineManager.setActiveQuality(model.id) onTriggered: Cura.MachineManager.setActiveQuality(model.id)
visible: model.available
} }
onObjectAdded: menu.insertItem(index, object); onObjectAdded: menu.insertItem(index, object);

View File

@ -9,6 +9,8 @@ import QtQuick.Layouts 1.1
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
import "../Menus"
Item Item
{ {
id: base; id: base;
@ -18,6 +20,88 @@ Item
signal showTooltip(Item item, point location, string text); signal showTooltip(Item item, point location, string text);
signal hideTooltip(); 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 += " <font color=\"" + UM.Theme.getColor("text_detail") + "\">";
result += " - ";
result += Cura.MachineManager.activeQualityLayerHeight + "mm";
result += "</font>";
}
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 Rectangle
{ {
id: filterContainer id: filterContainer
@ -40,7 +124,8 @@ Item
anchors anchors
{ {
top: parent.top top: globalProfileRow.bottom
topMargin: UM.Theme.getSize("sidebar_margin").height
left: parent.left left: parent.left
leftMargin: UM.Theme.getSize("sidebar_margin").width leftMargin: UM.Theme.getSize("sidebar_margin").width
right: parent.right right: parent.right

View File

@ -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 += " <font color=\"" + UM.Theme.getColor("text_detail") + "\">";
result += " - ";
result += Cura.MachineManager.activeQualityLayerHeight + "mm";
result += "</font>";
}
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 StackView
{ {
id: sidebarContents id: sidebarContents
anchors.bottom: footerSeparator.top anchors.bottom: footerSeparator.top
anchors.top: globalProfileRow.bottom anchors.top: settingsModeSelection.bottom
anchors.topMargin: UM.Theme.getSize("sidebar_margin").height anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
anchors.left: base.left anchors.left: base.left
anchors.right: base.right anchors.right: base.right

View File

@ -37,12 +37,385 @@ Item
height: childrenRect.height height: childrenRect.height
color: UM.Theme.getColor("sidebar") 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 Item
{ {
id: infillCellLeft 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.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 width: UM.Theme.getSize("sidebar").width * .45 - UM.Theme.getSize("sidebar_margin").width
height: childrenRect.height height: childrenRect.height
@ -71,6 +444,7 @@ Item
anchors.left: infillCellLeft.right anchors.left: infillCellLeft.right
anchors.top: infillCellLeft.top anchors.top: infillCellLeft.top
anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
Repeater Repeater
{ {

View File

@ -192,6 +192,12 @@
"topbar_button_text_inactive": [255, 255, 255, 255], "topbar_button_text_inactive": [255, 255, 255, 255],
"topbar_button_text_active": [255, 255, 255, 255], "topbar_button_text_active": [255, 255, 255, 255],
"topbar_button_text_hovered": [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]
} }
} }

View File

@ -196,6 +196,12 @@
"slider_handle_border": [39, 44, 48, 255], "slider_handle_border": [39, 44, 48, 255],
"slider_text_background": [255, 255, 255, 255], "slider_text_background": [255, 255, 255, 255],
"quality_slider_unavailable": [179, 179, 179, 255],
"quality_slider_available": [0, 0, 0, 255],
"quality_slider_handle": [0, 0, 0, 255],
"quality_slider_handle_hover": [127, 127, 127, 255],
"quality_slider_text": [0, 0, 0, 255],
"checkbox": [255, 255, 255, 255], "checkbox": [255, 255, 255, 255],
"checkbox_hover": [255, 255, 255, 255], "checkbox_hover": [255, 255, 255, 255],
"checkbox_border": [64, 69, 72, 255], "checkbox_border": [64, 69, 72, 255],
@ -338,6 +344,8 @@
"scrollbar": [0.75, 0.5], "scrollbar": [0.75, 0.5],
"quality_slider_bar": [1, 0.2],
"slider_groove": [0.3, 0.3], "slider_groove": [0.3, 0.3],
"slider_handle": [1.0, 1.0], "slider_handle": [1.0, 1.0],
"slider_layerview_size": [1.0, 22.0], "slider_layerview_size": [1.0, 22.0],