create separate layerslider component, fix updating when changing view

This commit is contained in:
ChrisTerBeke 2017-10-06 17:29:37 +02:00
parent 9f0b85952a
commit d435541908
3 changed files with 388 additions and 289 deletions

View file

@ -0,0 +1,273 @@
// 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"
// 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 getUpperValue () {
return upperHandle.getValue()
}
function setUpperValue (value) {
console.log("setUpperValue", value)
upperHandle.setValue(value)
updateRangeHandle()
}
function getLowerValue () {
return lowerHandle.getValue()
}
function setLowerValue (value) {
console.log("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
// the range slider is only dragged when the upper and lower sliders collide
function onHandleDragged () {
upperHandle.y = y - upperHandle.height
lowerHandle.y = y + height
var upperValue = sliderRoot.getUpperValue()
var lowerValue = upperValue - (sliderRoot.upperValue - sliderRoot.lowerValue)
// update the Python values
// TODO: improve this?
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 - (parent.heigth + 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 () {
console.log("upperhandle dragged")
// 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 rangle handle
rangeHandle.height = lowerHandle.y - (y + height)
// TODO: improve this?
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) {
console.log("setValue", value)
var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
var newUpperYPosition = Math.round(diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
y = newUpperYPosition
}
// dragging
MouseArea {
anchors.fill: parent
drag {
target: parent
axis: Drag.YAxis
minimumY: 0
maximumY: sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)
}
onPositionChanged: parent.onHandleDragged()
}
// UM.PointingRectangle {
//
// x: sliderRoot.width - UM.Theme.getSize("slider_layerview_background").width / 2 - width;
// y: Math.floor(((parent.y + parent.height) / 2) - (height / 2));
//
// target: Qt.point(parent.width, (parent.y + parent.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: sliderRoot.layersVisible
//
// // Catch all mouse events (so 3D scene doesn't handle them)
// MouseArea {
// anchors.fill: parent
// }
//
// TextField {
// id: upperValueLabel
//
// property string maximumValue: sliderRoot.maximumValue + 1
//
// text: sliderRoot.getUpperValue() + 1
// horizontalAlignment: TextInput.AlignRight
//
//
// }
// }
}
// 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
rangeHandle.height = y - (upperHandle.y + upperHandle.height)
// TODO: improve this?
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) {
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
}
// dragging
MouseArea {
anchors.fill: parent
drag {
target: parent
axis: Drag.YAxis
minimumY: upperHandle.height + sliderRoot.minimumRangeHandleSize
maximumY: sliderRoot.height - parent.height
}
onPositionChanged: parent.onHandleDragged()
}
}
}

View file

@ -9,6 +9,8 @@ import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM import UM 1.0 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
//import LayerSlider 1.0
Item Item
{ {
id: base id: base
@ -338,296 +340,121 @@ 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")
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 { // Item
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 // UM.PointingRectangle
// {
property real value: UM.LayerView.currentLayer // x: parent.width - UM.Theme.getSize("slider_layerview_background").width / 2 - width;
function setValue(value) // y: Math.floor(slider.activeHandle.y + slider.activeHandle.height / 2 - height / 2);
{ //
UM.LayerView.setCurrentLayer(value); // target: Qt.point(parent.width, slider.activeHandle.y + slider.activeHandle.height / 2)
} // arrowSize: UM.Theme.getSize("default_arrow").width
//
MouseArea { // height: UM.Theme.getSize("slider_handle").height + UM.Theme.getSize("default_margin").height
anchors.fill: parent // width: valueLabel.width + UM.Theme.getSize("default_margin").width
// Behavior on height { NumberAnimation { duration: 50; } }
drag.target: parent //
drag.axis: Drag.YAxis // color: UM.Theme.getColor("tool_panel_background")
drag.minimumY: 0 // borderColor: UM.Theme.getColor("lining")
drag.maximumY: parent.parent.height - (2 * parent.parent.handleSize + parent.parent.minimumRangeHandleSize) // borderWidth: UM.Theme.getSize("default_lining").width
//
onPressed: parent.parent.activeHandle = upperHandle // visible: slider.layersVisible
onPositionChanged: //
{ // MouseArea //Catch all mouse events (so scene doesnt handle them)
if(lowerHandle.y - (upperHandle.y + upperHandle.height) < parent.parent.minimumRangeHandleSize) // {
{ // anchors.fill: parent
lowerHandle.y = upperHandle.y + upperHandle.height + parent.parent.minimumRangeHandleSize; // }
} //
rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height); // TextField
// {
UM.LayerView.setCurrentLayer(slider.getUpperValueFromHandle()); // id: valueLabel
} // property string maxValue: slider.maximumValue + 1
} // text: slider.activeHandle.value + 1
} // horizontalAlignment: TextInput.AlignRight;
// onEditingFinished:
Rectangle { // {
id: lowerHandle // // Ensure that the cursor is at the first position. On some systems the text isn't fully visible
y: parent.height - parent.handleSize // // Seems to have to do something with different dpi densities that QML doesn't quite handle.
width: parent.handleSize // // Another option would be to increase the size even further, but that gives pretty ugly results.
height: parent.handleSize // cursorPosition = 0;
anchors.horizontalCenter: parent.horizontalCenter // if(valueLabel.text != '')
radius: parent.handleRadius // {
color: parent.lowerHandleColor // slider.activeHandle.setValue(valueLabel.text - 1);
// border.width: UM.Theme.getSize("default_lining").width // }
// border.color: UM.Theme.getColor("slider_handle_border") // }
// validator: IntValidator { bottom: 1; top: slider.maximumValue + 1; }
visible: slider.layersVisible //
// anchors.left: parent.left;
property real value: UM.LayerView.minimumLayer // anchors.leftMargin: UM.Theme.getSize("default_margin").width / 2;
function setValue(value) // anchors.verticalCenter: parent.verticalCenter;
{ //
UM.LayerView.setMinimumLayer(value); // width: Math.max(UM.Theme.getSize("line").width * maxValue.length + 2 * screenScaleFactor, 20 * screenScaleFactor);
} // style: TextFieldStyle
// {
MouseArea { // textColor: UM.Theme.getColor("setting_control_text");
anchors.fill: parent // font: UM.Theme.getFont("default");
// background: Item { }
drag.target: parent // }
drag.axis: Drag.YAxis //
drag.minimumY: upperHandle.height + parent.parent.minimumRangeHandleSize // Keys.onUpPressed: slider.activeHandle.setValue(slider.activeHandle.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
drag.maximumY: parent.parent.height - parent.height // Keys.onDownPressed: slider.activeHandle.setValue(slider.activeHandle.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
// }
onPressed: parent.parent.activeHandle = lowerHandle //
onPositionChanged: // BusyIndicator
{ // {
if(lowerHandle.y - (upperHandle.y + upperHandle.height) < parent.parent.minimumRangeHandleSize) // id: busyIndicator;
{ // anchors.left: parent.right;
upperHandle.y = lowerHandle.y - (upperHandle.height + parent.parent.minimumRangeHandleSize); // anchors.leftMargin: UM.Theme.getSize("default_margin").width / 2;
} // anchors.verticalCenter: parent.verticalCenter;
rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height) //
// width: UM.Theme.getSize("slider_handle").height;
UM.LayerView.setMinimumLayer(slider.getLowerValueFromHandle()); // height: width;
} //
} // running: UM.LayerView.busy;
} // visible: UM.LayerView.busy;
// }
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: Math.max(UM.Theme.getSize("line").width * maxValue.length + 2 * screenScaleFactor, 20 * screenScaleFactor);
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)