// Copyright (c) 2015 Ultimaker B.V. // Cura is released under the terms of the AGPLv3 or higher. import QtQuick 2.2 import QtQuick.Controls 1.2 import QtQuick.Layouts 1.1 import QtQuick.Controls.Styles 1.1 import UM 1.0 as UM Item { width: { if (UM.LayerView.compatibilityMode) { return UM.Theme.getSize("layerview_menu_size_compatibility").width; } else { return UM.Theme.getSize("layerview_menu_size").width; } } height: { if (UM.LayerView.compatibilityMode) { return UM.Theme.getSize("layerview_menu_size_compatibility").height; } else { return UM.Theme.getSize("layerview_menu_size").height + UM.LayerView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height) } } Rectangle { id: layerViewMenu anchors.left: parent.left anchors.top: parent.top width: parent.width height: parent.height z: slider.z - 1 color: UM.Theme.getColor("tool_panel_background") ColumnLayout { id: view_settings property var extruder_opacities: UM.Preferences.getValue("layerview/extruder_opacities").split("|") property bool show_travel_moves: UM.Preferences.getValue("layerview/show_travel_moves") property bool show_helpers: UM.Preferences.getValue("layerview/show_helpers") property bool show_skin: UM.Preferences.getValue("layerview/show_skin") property bool show_infill: UM.Preferences.getValue("layerview/show_infill") property bool show_legend: UM.LayerView.compatibilityMode || UM.Preferences.getValue("layerview/layer_view_type") == 1 property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers") property int top_layer_count: UM.Preferences.getValue("view/top_layer_count") anchors.top: parent.top anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("layerview_row_spacing").height Label { id: layersLabel anchors.left: parent.left text: catalog.i18nc("@label","View Mode: Layers") font.bold: true style: UM.Theme.styles.text } Label { id: spaceLabel anchors.left: parent.left text: " " font.pointSize: 0.5 } Label { id: layerViewTypesLabel anchors.left: parent.left text: catalog.i18nc("@label","Color scheme") visible: !UM.LayerView.compatibilityMode Layout.fillWidth: true style: UM.Theme.styles.text } ListModel // matches LayerView.py { id: layerViewTypes } Component.onCompleted: { layerViewTypes.append({ text: catalog.i18nc("@label:listbox", "Material Color"), type_id: 0 }) layerViewTypes.append({ text: catalog.i18nc("@label:listbox", "Line Type"), type_id: 1 // these ids match the switching in the shader }) } ComboBox { id: layerTypeCombobox anchors.left: parent.left Layout.fillWidth: true Layout.preferredWidth: UM.Theme.getSize("layerview_row").width model: layerViewTypes visible: !UM.LayerView.compatibilityMode style: UM.Theme.styles.combobox property int layer_view_type: UM.Preferences.getValue("layerview/layer_view_type") currentIndex: layer_view_type // index matches type_id onActivated: { // Combobox selection var type_id = index; UM.Preferences.setValue("layerview/layer_view_type", type_id); updateLegend(type_id); } onModelChanged: { updateLegend(UM.Preferences.getValue("layerview/layer_view_type")); } // Update visibility of legend. function updateLegend(type_id) { if (UM.LayerView.compatibilityMode || (type_id == 1)) { // Line type view_settings.show_legend = true; } else { view_settings.show_legend = false; } } } Label { id: compatibilityModeLabel anchors.left: parent.left text: catalog.i18nc("@label","Compatibility Mode") visible: UM.LayerView.compatibilityMode Layout.fillWidth: true Layout.preferredHeight: UM.Theme.getSize("layerview_row").height Layout.preferredWidth: UM.Theme.getSize("layerview_row").width } Label { id: space2Label anchors.left: parent.left text: " " font.pointSize: 0.5 } Connections { target: UM.Preferences onPreferenceChanged: { layerTypeCombobox.layer_view_type = UM.Preferences.getValue("layerview/layer_view_type"); view_settings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|"); view_settings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves"); view_settings.show_helpers = UM.Preferences.getValue("layerview/show_helpers"); view_settings.show_skin = UM.Preferences.getValue("layerview/show_skin"); view_settings.show_infill = UM.Preferences.getValue("layerview/show_infill"); view_settings.only_show_top_layers = UM.Preferences.getValue("view/only_show_top_layers"); view_settings.top_layer_count = UM.Preferences.getValue("view/top_layer_count"); } } Repeater { model: UM.LayerView.extruderCount CheckBox { checked: view_settings.extruder_opacities[index] > 0.5 || view_settings.extruder_opacities[index] == undefined || view_settings.extruder_opacities[index] == "" onClicked: { view_settings.extruder_opacities[index] = checked ? 1.0 : 0.0 UM.Preferences.setValue("layerview/extruder_opacities", view_settings.extruder_opacities.join("|")); } text: catalog.i18nc("@label", "Extruder %1").arg(index + 1) visible: !UM.LayerView.compatibilityMode enabled: index + 1 <= 4 Layout.fillWidth: true Layout.preferredHeight: UM.Theme.getSize("layerview_row").height Layout.preferredWidth: UM.Theme.getSize("layerview_row").width style: UM.Theme.styles.checkbox } } CheckBox { checked: view_settings.show_travel_moves onClicked: { UM.Preferences.setValue("layerview/show_travel_moves", checked); } text: catalog.i18nc("@label", "Show Travels") Rectangle { anchors.top: parent.top anchors.topMargin: 2 anchors.right: parent.right width: UM.Theme.getSize("layerview_legend_size").width height: UM.Theme.getSize("layerview_legend_size").height color: UM.Theme.getColor("layerview_move_combing") border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") visible: view_settings.show_legend } Layout.fillWidth: true Layout.preferredHeight: UM.Theme.getSize("layerview_row").height Layout.preferredWidth: UM.Theme.getSize("layerview_row").width style: UM.Theme.styles.checkbox } CheckBox { checked: view_settings.show_helpers onClicked: { UM.Preferences.setValue("layerview/show_helpers", checked); } text: catalog.i18nc("@label", "Show Helpers") Rectangle { anchors.top: parent.top anchors.topMargin: 2 anchors.right: parent.right width: UM.Theme.getSize("layerview_legend_size").width height: UM.Theme.getSize("layerview_legend_size").height color: UM.Theme.getColor("layerview_support") border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") visible: view_settings.show_legend } Layout.fillWidth: true Layout.preferredHeight: UM.Theme.getSize("layerview_row").height Layout.preferredWidth: UM.Theme.getSize("layerview_row").width style: UM.Theme.styles.checkbox } CheckBox { checked: view_settings.show_skin onClicked: { UM.Preferences.setValue("layerview/show_skin", checked); } text: catalog.i18nc("@label", "Show Shell") Rectangle { anchors.top: parent.top anchors.topMargin: 2 anchors.right: parent.right width: UM.Theme.getSize("layerview_legend_size").width height: UM.Theme.getSize("layerview_legend_size").height color: UM.Theme.getColor("layerview_inset_0") border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") visible: view_settings.show_legend } Layout.fillWidth: true Layout.preferredHeight: UM.Theme.getSize("layerview_row").height Layout.preferredWidth: UM.Theme.getSize("layerview_row").width style: UM.Theme.styles.checkbox } CheckBox { checked: view_settings.show_infill onClicked: { UM.Preferences.setValue("layerview/show_infill", checked); } text: catalog.i18nc("@label", "Show Infill") Rectangle { anchors.top: parent.top anchors.topMargin: 2 anchors.right: parent.right width: UM.Theme.getSize("layerview_legend_size").width height: UM.Theme.getSize("layerview_legend_size").height color: UM.Theme.getColor("layerview_infill") border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") visible: view_settings.show_legend } Layout.fillWidth: true Layout.preferredHeight: UM.Theme.getSize("layerview_row").height Layout.preferredWidth: UM.Theme.getSize("layerview_row").width style: UM.Theme.styles.checkbox } CheckBox { checked: view_settings.only_show_top_layers onClicked: { UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0); } text: catalog.i18nc("@label", "Only Show Top Layers") visible: UM.LayerView.compatibilityMode style: UM.Theme.styles.checkbox } CheckBox { checked: view_settings.top_layer_count == 5 onClicked: { UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1); } text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top") visible: UM.LayerView.compatibilityMode style: UM.Theme.styles.checkbox } Label { id: topBottomLabel anchors.left: parent.left text: catalog.i18nc("@label","Top / Bottom") Rectangle { anchors.top: parent.top anchors.topMargin: 2 anchors.right: parent.right width: UM.Theme.getSize("layerview_legend_size").width height: UM.Theme.getSize("layerview_legend_size").height color: UM.Theme.getColor("layerview_skin") border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") } Layout.fillWidth: true Layout.preferredHeight: UM.Theme.getSize("layerview_row").height Layout.preferredWidth: UM.Theme.getSize("layerview_row").width visible: view_settings.show_legend style: UM.Theme.styles.text } Label { id: innerWallLabel anchors.left: parent.left text: catalog.i18nc("@label","Inner Wall") Rectangle { anchors.top: parent.top anchors.topMargin: 2 anchors.right: parent.right width: UM.Theme.getSize("layerview_legend_size").width height: UM.Theme.getSize("layerview_legend_size").height color: UM.Theme.getColor("layerview_inset_x") border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") visible: view_settings.show_legend } Layout.fillWidth: true Layout.preferredHeight: UM.Theme.getSize("layerview_row").height Layout.preferredWidth: UM.Theme.getSize("layerview_row").width visible: view_settings.show_legend style: UM.Theme.styles.text } } Item { id: slider width: handleSize height: parent.height - 2*UM.Theme.getSize("slider_layerview_margin").height anchors.top: parent.top anchors.topMargin: UM.Theme.getSize("slider_layerview_margin").height anchors.right: layerViewMenu.right anchors.rightMargin: UM.Theme.getSize("slider_layerview_margin").width property real handleSize: UM.Theme.getSize("slider_handle").width property real handleRadius: handleSize / 2 property real minimumRangeHandleSize: UM.Theme.getSize("slider_handle").width / 2 property real trackThickness: UM.Theme.getSize("slider_groove").width property real trackRadius: trackThickness / 2 property real trackBorderWidth: UM.Theme.getSize("default_lining").width property color upperHandleColor: UM.Theme.getColor("slider_handle") property color lowerHandleColor: UM.Theme.getColor("slider_handle") property color rangeHandleColor: UM.Theme.getColor("slider_groove_fill") property color trackColor: UM.Theme.getColor("slider_groove") property color trackBorderColor: UM.Theme.getColor("slider_groove_border") property real maximumValue: UM.LayerView.numLayers property real minimumValue: 0 property real minimumRange: 0 property bool roundValues: true property var activeHandle: upperHandle property bool layersVisible: UM.LayerView.layerActivity && Printer.platformActivity ? true : false function getUpperValueFromHandle() { var result = upperHandle.y / (height - (2 * handleSize + minimumRangeHandleSize)); result = maximumValue + result * (minimumValue - (maximumValue - minimumRange)); result = roundValues ? Math.round(result) | 0 : result; return result; } function getLowerValueFromHandle() { var result = (lowerHandle.y - (handleSize + minimumRangeHandleSize)) / (height - (2 * handleSize + minimumRangeHandleSize)); result = maximumValue - minimumRange + result * (minimumValue - (maximumValue - minimumRange)); result = roundValues ? Math.round(result) : result; return result; } function setUpperValue(value) { var value = (value - maximumValue) / (minimumValue - maximumValue); var new_upper_y = Math.round(value * (height - (2 * handleSize + minimumRangeHandleSize))); if(new_upper_y != upperHandle.y) { upperHandle.y = new_upper_y; } rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height); } function setLowerValue(value) { var value = (value - maximumValue) / (minimumValue - maximumValue); var new_lower_y = Math.round((handleSize + minimumRangeHandleSize) + value * (height - (2 * handleSize + minimumRangeHandleSize))); if(new_lower_y != lowerHandle.y) { lowerHandle.y = new_lower_y; } rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height); } Connections { target: UM.LayerView onMinimumLayerChanged: slider.setLowerValue(UM.LayerView.minimumLayer) onCurrentLayerChanged: slider.setUpperValue(UM.LayerView.currentLayer) } Rectangle { width: parent.trackThickness height: parent.height - parent.handleSize radius: parent.trackRadius anchors.centerIn: parent color: parent.trackColor border.width: parent.trackBorderWidth; border.color: parent.trackBorderColor; } Item { id: rangeHandle y: upperHandle.y + upperHandle.height width: parent.handleSize height: parent.minimumRangeHandleSize anchors.horizontalCenter: parent.horizontalCenter visible: slider.layersVisible property real value: UM.LayerView.currentLayer function setValue(value) { var range = upperHandle.value - lowerHandle.value; value = Math.min(value, slider.maximumValue); value = Math.max(value, slider.minimumValue + range); UM.LayerView.setCurrentLayer(value); UM.LayerView.setMinimumLayer(value - range); } Rectangle { anchors.centerIn: parent width: parent.parent.trackThickness - 2 * parent.parent.trackBorderWidth height: parent.height + parent.parent.handleSize color: parent.parent.rangeHandleColor } MouseArea { anchors.fill: parent drag.target: parent drag.axis: Drag.YAxis drag.minimumY: upperHandle.height drag.maximumY: parent.parent.height - (parent.height + lowerHandle.height) onPressed: parent.parent.activeHandle = rangeHandle onPositionChanged: { upperHandle.y = parent.y - upperHandle.height lowerHandle.y = parent.y + parent.height var upper_value = slider.getUpperValueFromHandle(); var lower_value = upper_value - (upperHandle.value - lowerHandle.value); UM.LayerView.setCurrentLayer(upper_value); UM.LayerView.setMinimumLayer(lower_value); } } } Rectangle { id: upperHandle y: parent.height - (parent.minimumRangeHandleSize + 2 * parent.handleSize) width: parent.handleSize height: parent.handleSize anchors.horizontalCenter: parent.horizontalCenter radius: parent.handleRadius color: parent.upperHandleColor visible: slider.layersVisible property real value: UM.LayerView.currentLayer function setValue(value) { UM.LayerView.setCurrentLayer(value); } MouseArea { anchors.fill: parent drag.target: parent drag.axis: Drag.YAxis drag.minimumY: 0 drag.maximumY: parent.parent.height - (2 * parent.parent.handleSize + parent.parent.minimumRangeHandleSize) onPressed: parent.parent.activeHandle = upperHandle onPositionChanged: { if(lowerHandle.y - (upperHandle.y + upperHandle.height) < parent.parent.minimumRangeHandleSize) { lowerHandle.y = upperHandle.y + upperHandle.height + parent.parent.minimumRangeHandleSize; } rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height); UM.LayerView.setCurrentLayer(slider.getUpperValueFromHandle()); } } } Rectangle { id: lowerHandle y: parent.height - parent.handleSize width: parent.handleSize height: parent.handleSize anchors.horizontalCenter: parent.horizontalCenter radius: parent.handleRadius color: parent.lowerHandleColor visible: slider.layersVisible property real value: UM.LayerView.minimumLayer function setValue(value) { UM.LayerView.setMinimumLayer(value); } MouseArea { anchors.fill: parent drag.target: parent drag.axis: Drag.YAxis drag.minimumY: upperHandle.height + parent.parent.minimumRangeHandleSize drag.maximumY: parent.parent.height - parent.height onPressed: parent.parent.activeHandle = lowerHandle onPositionChanged: { if(lowerHandle.y - (upperHandle.y + upperHandle.height) < parent.parent.minimumRangeHandleSize) { upperHandle.y = lowerHandle.y - (upperHandle.height + parent.parent.minimumRangeHandleSize); } rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height) UM.LayerView.setMinimumLayer(slider.getLowerValueFromHandle()); } } } UM.PointingRectangle { x: parent.width + UM.Theme.getSize("slider_layerview_background").width / 2; y: Math.floor(slider.activeHandle.y + slider.activeHandle.height / 2 - height / 2); target: Qt.point(0, slider.activeHandle.y + slider.activeHandle.height / 2) arrowSize: UM.Theme.getSize("default_arrow").width height: (Math.floor(UM.Theme.getSize("slider_handle").height + UM.Theme.getSize("default_margin").height) / 2) * 2 // Make sure height has an integer middle so drawing a pointy border is easier width: valueLabel.width + UM.Theme.getSize("default_margin").width Behavior on height { NumberAnimation { duration: 50; } } color: UM.Theme.getColor("lining"); visible: slider.layersVisible UM.PointingRectangle { color: UM.Theme.getColor("tool_panel_background") target: Qt.point(0, height / 2 + UM.Theme.getSize("default_lining").width) arrowSize: UM.Theme.getSize("default_arrow").width anchors.fill: parent anchors.margins: UM.Theme.getSize("default_lining").width MouseArea //Catch all mouse events (so scene doesnt handle them) { anchors.fill: parent } } TextField { id: valueLabel property string maxValue: slider.maximumValue + 1 text: slider.activeHandle.value + 1 horizontalAlignment: TextInput.AlignRight; onEditingFinished: { // Ensure that the cursor is at the first position. On some systems the text isn't fully visible // Seems to have to do something with different dpi densities that QML doesn't quite handle. // Another option would be to increase the size even further, but that gives pretty ugly results. cursorPosition = 0; if(valueLabel.text != '') { slider.activeHandle.setValue(valueLabel.text - 1); } } validator: IntValidator { bottom: 1; top: slider.maximumValue + 1; } anchors.left: parent.left; anchors.leftMargin: UM.Theme.getSize("default_margin").width / 2; anchors.verticalCenter: parent.verticalCenter; width: Math.max(UM.Theme.getSize("line").width * maxValue.length + 2, 20); style: TextFieldStyle { textColor: UM.Theme.getColor("setting_control_text"); font: UM.Theme.getFont("default"); background: Item { } } Keys.onUpPressed: slider.activeHandle.setValue(slider.activeHandle.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1)) Keys.onDownPressed: slider.activeHandle.setValue(slider.activeHandle.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1)) } BusyIndicator { id: busyIndicator; anchors.left: parent.right; anchors.leftMargin: UM.Theme.getSize("default_margin").width / 2; anchors.verticalCenter: parent.verticalCenter; width: UM.Theme.getSize("slider_handle").height; height: width; running: UM.LayerView.busy; visible: UM.LayerView.busy; } } } } }