This commit is contained in:
ChrisTerBeke 2017-10-10 16:31:04 +02:00
commit 1b0576947d
4 changed files with 414 additions and 289 deletions

View File

@ -0,0 +1,278 @@
// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 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
import Cura 1.0 as Cura
Item {
id: sliderRoot
// handle properties
property real handleSize: 10
property real handleRadius: handleSize / 2
property real minimumRangeHandleSize: handleSize / 2
property color upperHandleColor: "black"
property color lowerHandleColor: "black"
property color rangeHandleColor: "black"
property real handleLabelWidth: width
// track properties
property real trackThickness: 4 // width of the slider track
property real trackRadius: trackThickness / 2
property color trackColor: "white"
property real trackBorderWidth: 1 // width of the slider track border
property color trackBorderColor: "black"
// value properties
property real maximumValue: 100
property real minimumValue: 0
property real minimumRange: 0 // minimum range allowed between min and max values
property bool roundValues: true
property real upperValue: maximumValue
property real lowerValue: minimumValue
property bool layersVisible: true
function getUpperValueFromSliderHandle () {
return upperHandle.getValue()
}
function setUpperValue (value) {
upperHandle.setValue(value)
updateRangeHandle()
}
function getLowerValueFromSliderHandle () {
return lowerHandle.getValue()
}
function setLowerValue (value) {
lowerHandle.setValue(value)
updateRangeHandle()
}
function updateRangeHandle () {
rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height)
}
// slider track
Rectangle {
id: track
width: sliderRoot.trackThickness
height: sliderRoot.height - sliderRoot.handleSize
radius: sliderRoot.trackRadius
anchors.centerIn: sliderRoot
color: sliderRoot.trackColor
border.width: sliderRoot.trackBorderWidth
border.color: sliderRoot.trackBorderColor
visible: sliderRoot.layersVisible
}
// Range handle
Item {
id: rangeHandle
y: upperHandle.y + upperHandle.height
width: sliderRoot.handleSize
height: sliderRoot.minimumRangeHandleSize
anchors.horizontalCenter: sliderRoot.horizontalCenter
visible: sliderRoot.layersVisible
// set the new value when dragging
function onHandleDragged () {
upperHandle.y = y - upperHandle.height
lowerHandle.y = y + height
var upperValue = sliderRoot.getUpperValueFromSliderHandle()
var lowerValue = sliderRoot.getLowerValueFromSliderHandle()
// set both values after moving the handle position
UM.LayerView.setCurrentLayer(upperValue)
UM.LayerView.setMinimumLayer(lowerValue)
}
Rectangle {
width: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth
height: parent.height + sliderRoot.handleSize
anchors.centerIn: parent
color: sliderRoot.rangeHandleColor
}
MouseArea {
anchors.fill: parent
drag {
target: parent
axis: Drag.YAxis
minimumY: upperHandle.height
maximumY: sliderRoot.height - (rangeHandle.height + lowerHandle.height)
}
onPositionChanged: parent.onHandleDragged()
}
}
// Upper handle
Rectangle {
id: upperHandle
y: sliderRoot.height - (sliderRoot.minimumRangeHandleSize + 2 * sliderRoot.handleSize)
width: sliderRoot.handleSize
height: sliderRoot.handleSize
anchors.horizontalCenter: sliderRoot.horizontalCenter
radius: sliderRoot.handleRadius
color: sliderRoot.upperHandleColor
visible: sliderRoot.layersVisible
function onHandleDragged () {
// don't allow the lower handle to be heigher than the upper handle
if (lowerHandle.y - (y + height) < sliderRoot.minimumRangeHandleSize) {
lowerHandle.y = y + height + sliderRoot.minimumRangeHandleSize
}
// update the range handle
sliderRoot.updateRangeHandle()
// set the new value after moving the handle position
UM.LayerView.setCurrentLayer(getValue())
}
// get the upper value based on the slider position
function getValue () {
var result = y / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize))
result = sliderRoot.maximumValue + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumValue))
result = sliderRoot.roundValues ? Math.round(result) : result
return result
}
// set the slider position based on the upper value
function setValue (value) {
UM.LayerView.setCurrentLayer(value)
var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
var newUpperYPosition = Math.round(diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
y = newUpperYPosition
// update the range handle
sliderRoot.updateRangeHandle()
}
// dragging
MouseArea {
anchors.fill: parent
drag {
target: parent
axis: Drag.YAxis
minimumY: 0
maximumY: sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)
}
onPositionChanged: parent.onHandleDragged()
}
LayerSliderLabel {
id: upperHandleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
x: parent.x - width - UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter
target: Qt.point(sliderRoot.width, y + height / 2)
visible: sliderRoot.layersVisible
// custom properties
maximumValue: sliderRoot.maximumValue
value: sliderRoot.upperValue
busy: UM.LayerView.busy
setValue: sliderRoot.setUpperValue // connect callback functions
}
}
// Lower handle
Rectangle {
id: lowerHandle
y: sliderRoot.height - sliderRoot.handleSize
width: parent.handleSize
height: parent.handleSize
anchors.horizontalCenter: parent.horizontalCenter
radius: sliderRoot.handleRadius
color: sliderRoot.lowerHandleColor
visible: slider.layersVisible
function onHandleDragged () {
// don't allow the upper handle to be lower than the lower handle
if (y - (upperHandle.y + upperHandle.height) < sliderRoot.minimumRangeHandleSize) {
upperHandle.y = y - (upperHandle.heigth + sliderRoot.minimumRangeHandleSize)
}
// update the range handle
sliderRoot.updateRangeHandle()
// set the new value after moving the handle position
UM.LayerView.setMinimumLayer(getValue())
}
// get the lower value from the current slider position
function getValue () {
var result = (y - (sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)) / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize));
result = sliderRoot.maximumValue - sliderRoot.minimumRange + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumRange))
result = sliderRoot.roundValues ? Math.round(result) : result
return result
}
// set the slider position based on the lower value
function setValue (value) {
UM.LayerView.setMinimumLayer(value)
var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
var newLowerYPosition = Math.round((sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize) + diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
y = newLowerYPosition
// update the range handle
sliderRoot.updateRangeHandle()
}
// dragging
MouseArea {
anchors.fill: parent
drag {
target: parent
axis: Drag.YAxis
minimumY: upperHandle.height + sliderRoot.minimumRangeHandleSize
maximumY: sliderRoot.height - parent.height
}
onPositionChanged: parent.onHandleDragged()
}
LayerSliderLabel {
id: lowerHandleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
x: parent.x - width - UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter
target: Qt.point(sliderRoot.width, y + height / 2)
visible: sliderRoot.layersVisible
// custom properties
maximumValue: sliderRoot.maximumValue
value: sliderRoot.lowerValue
busy: UM.LayerView.busy
setValue: sliderRoot.setLowerValue // connect callback functions
}
}
}

View File

@ -0,0 +1,99 @@
// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 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
import Cura 1.0 as Cura
UM.PointingRectangle {
id: sliderLabelRoot
// custom properties
property real maximumValue: 100
property real value: 0
property var setValue // Function
property bool busy: false
target: Qt.point(parent.width, y + height / 2)
arrowSize: UM.Theme.getSize("default_arrow").width
height: parent.height
width: valueLabel.width + UM.Theme.getSize("default_margin").width
color: UM.Theme.getColor("tool_panel_background")
borderColor: UM.Theme.getColor("lining")
borderWidth: UM.Theme.getSize("default_lining").width
visible: true
Behavior on height {
NumberAnimation {
duration: 50
}
}
// catch all mouse events so they're not handled by underlying 3D scene
MouseArea {
anchors.fill: parent
}
TextField {
id: valueLabel
anchors {
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width / 2
verticalCenter: parent.verticalCenter
}
width: 40 * screenScaleFactor
text: sliderLabelRoot.value + 1 // the current handle value, add 1 because layers is an array
horizontalAlignment: TextInput.AlignRight
style: TextFieldStyle {
textColor: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
background: Item { }
}
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 != "") {
// -1 because we need to convert back to an array structure
sliderLabelRoot.setValue(parseInt(valueLabel.text) - 1)
}
}
validator: IntValidator {
bottom: 1
top: sliderLabelRoot.maximumValue + 1 // +1 because actual layers is an array
}
Keys.onUpPressed: sliderLabelRoot.setValue(sliderLabelRoot.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
Keys.onDownPressed: sliderLabelRoot.setValue(sliderLabelRoot.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
}
BusyIndicator {
id: busyIndicator
anchors {
left: parent.right
leftMargin: UM.Theme.getSize("default_margin").width / 2
verticalCenter: parent.verticalCenter
}
width: sliderLabelRoot.height
height: width
visible: sliderLabelRoot.busy
running: sliderLabelRoot.busy
}
}

View File

@ -338,295 +338,44 @@ Item
} }
} }
Item LayerSlider {
{
id: slider id: slider
width: handleSize
width: UM.Theme.getSize("slider_handle").width
height: UM.Theme.getSize("layerview_menu_size").height height: UM.Theme.getSize("layerview_menu_size").height
anchors.top: parent.bottom
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 anchors {
property real handleRadius: handleSize / 2 top: parent.bottom
property real minimumRangeHandleSize: UM.Theme.getSize("slider_handle").width / 2 topMargin: UM.Theme.getSize("slider_layerview_margin").height
property real trackThickness: UM.Theme.getSize("slider_groove").width right: layerViewMenu.right
property real trackRadius: trackThickness / 2 rightMargin: UM.Theme.getSize("slider_layerview_margin").width
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 && CuraApplication.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() // custom properties
{ upperValue: UM.LayerView.currentLayer
var result = (lowerHandle.y - (handleSize + minimumRangeHandleSize)) / (height - (2 * handleSize + minimumRangeHandleSize)); lowerValue: UM.LayerView.minimumLayer
result = maximumValue - minimumRange + result * (minimumValue - (maximumValue - minimumRange)); maximumValue: UM.LayerView.numLayers
result = roundValues ? Math.round(result) : result; handleSize: UM.Theme.getSize("slider_handle").width
return result; trackThickness: UM.Theme.getSize("slider_groove").width
} trackColor: UM.Theme.getColor("slider_groove")
trackBorderColor: UM.Theme.getColor("slider_groove_border")
upperHandleColor: UM.Theme.getColor("slider_handle")
lowerHandleColor: UM.Theme.getColor("slider_handle")
rangeHandleColor: UM.Theme.getColor("slider_groove_fill")
handleLabelWidth: UM.Theme.getSize("slider_layerview_background").width
layersVisible: UM.LayerView.layerActivity && CuraApplication.platformActivity ? true : false
function setUpperValue(value) // update values when layer data changes
{ Connections {
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 target: UM.LayerView
onMinimumLayerChanged: slider.setLowerValue(UM.LayerView.minimumLayer) onMinimumLayerChanged: slider.setLowerValue(UM.LayerView.minimumLayer)
onCurrentLayerChanged: slider.setUpperValue(UM.LayerView.currentLayer) onCurrentLayerChanged: slider.setUpperValue(UM.LayerView.currentLayer)
} }
Rectangle { // make sure the slider handlers show the correct value after switching views
width: parent.trackThickness Component.onCompleted: {
height: parent.height - parent.handleSize slider.setLowerValue(UM.LayerView.minimumLayer)
radius: parent.trackRadius slider.setUpperValue(UM.LayerView.currentLayer)
anchors.centerIn: parent
color: parent.trackColor
border.width: parent.trackBorderWidth;
border.color: parent.trackBorderColor;
visible: slider.layersVisible
}
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
//border.width: UM.Theme.getSize("default_lining").width
//border.color: UM.Theme.getColor("slider_handle_border")
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
// border.width: UM.Theme.getSize("default_lining").width
// border.color: UM.Theme.getColor("slider_handle_border")
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 - width;
y: Math.floor(slider.activeHandle.y + slider.activeHandle.height / 2 - height / 2);
target: Qt.point(parent.width, slider.activeHandle.y + slider.activeHandle.height / 2)
arrowSize: UM.Theme.getSize("default_arrow").width
height: UM.Theme.getSize("slider_handle").height + UM.Theme.getSize("default_margin").height
width: valueLabel.width + UM.Theme.getSize("default_margin").width
Behavior on height { NumberAnimation { duration: 50; } }
color: UM.Theme.getColor("tool_panel_background")
borderColor: UM.Theme.getColor("lining")
borderWidth: UM.Theme.getSize("default_lining").width
visible: slider.layersVisible
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: fontMetrics.averageCharacterWidth * (maxValue.length) + UM.Theme.getSize("default_margin").width;
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;
}
} }
} }
} }

View File

@ -18,6 +18,7 @@ class LayerViewProxy(QObject):
activityChanged = pyqtSignal() activityChanged = pyqtSignal()
globalStackChanged = pyqtSignal() globalStackChanged = pyqtSignal()
preferencesChanged = pyqtSignal() preferencesChanged = pyqtSignal()
busyChanged = pyqtSignal()
@pyqtProperty(bool, notify=activityChanged) @pyqtProperty(bool, notify=activityChanged)
def layerActivity(self): def layerActivity(self):
@ -43,7 +44,6 @@ class LayerViewProxy(QObject):
if type(active_view) == LayerView.LayerView.LayerView: if type(active_view) == LayerView.LayerView.LayerView:
return active_view.getMinimumLayer() return active_view.getMinimumLayer()
busyChanged = pyqtSignal()
@pyqtProperty(bool, notify=busyChanged) @pyqtProperty(bool, notify=busyChanged)
def busy(self): def busy(self):
active_view = self._controller.getActiveView() active_view = self._controller.getActiveView()
@ -57,7 +57,6 @@ class LayerViewProxy(QObject):
active_view = self._controller.getActiveView() active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView: if type(active_view) == LayerView.LayerView.LayerView:
return active_view.getCompatibilityMode() return active_view.getCompatibilityMode()
return False return False
@pyqtSlot(int) @pyqtSlot(int)