Reputation: 415
I'm looking to achieve a "snap while dragging" behavior in QML. Specifically, within my example below, when the element being dragged (red column) reaches a location on the x axis that is inside the "snap area" (orange column), it snaps to the middle of the snap area and sticks there until the mouse pointer is again outside the snap area, at which point the dragged element should snap to the current position of the mouse pointer and the drag continues on it's way. Here is what I have so far:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id: main_window
width: 640
height: 480
visible: true
visibility: Window.Maximized
property double x_location: square.x
property double y_location: square.y
property double start_x_of_snap_area: snap_area.x
property double end_x_of_snap_area: snap_area.x + snap_area.width
property bool is_handlebar_inside_snap_area: false
onX_locationChanged: function () {
if (x_location >= start_x_of_snap_area
&& square.x + square.width <= end_x_of_snap_area) {
is_handlebar_inside_snap_area = true
} else {
is_handlebar_inside_snap_area = false
}
}
onIs_handlebar_inside_snap_areaChanged: function () {
if (is_handlebar_inside_snap_area === true) {
console.log(dragArea.drag.target)
dragArea.drag.target = null
square.anchors.horizontalCenter = snap_area.horizontalCenter
}
}
Text {
y: 0
text: "start_x_of_snap_area: " + start_x_of_snap_area
font.pixelSize: 30
}
Text {
y: 50
text: "end_x_of_snap_area: " + end_x_of_snap_area
font.pixelSize: 30
}
Text {
y: 100
text: "is_handlebar_inside_snap_area: " + is_handlebar_inside_snap_area
font.pixelSize: 30
}
Rectangle {
id: snap_area
height: parent.height
width: 200
anchors.centerIn: parent
color: 'orange'
Text {
text: "snap area"
font.pixelSize: 30
anchors.centerIn: parent
}
}
Rectangle {
id: square
width: 50
height: main_window.height
color: 'red'
opacity: .7
Drag.active: dragArea.drag.active
Text {
text: 'x: ' + x_location + ' y: ' + y_location
font.pixelSize: 10
color: 'white'
anchors.centerIn: parent
font.family: 'Arial'
}
MouseArea {
id: dragArea
drag {
target: parent
axis: "XAxis"
minimumX: 0
maximumX: main_window.width - square.width
}
anchors.fill: parent
cursorShape: Qt.SizeAllCursor
}
}
}
Some problems with the above code is once the snap happens, its stuck. Also, if you move the mouse pointer really fast over the snap area the function doesn't fire quick enough to give satisfactory results (it doesn't work at all).
Upvotes: 0
Views: 919
Reputation: 1514
When you enter snap area you are deactivating mouse drag so it is stuck to there. In order to show a prospective location and actual moving object you should have at least one place holder.
You can simply bind is_handlebar_inside_snap_area
to x location. Here the solution should work for your case.
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id: main_window
width: 640
height: 480
visible: true
property int end_x_of_snap_area: snap_area.x + snap_area.width
property bool is_handlebar_inside_snap_area: square.x >= snap_area.x &&
square.x+square.width <= end_x_of_snap_area
property bool is_dragging: dragArea.drag.active
Rectangle {
id: snap_area
height: parent.height
width: 200
anchors.centerIn: parent
color: 'orange'
}
Rectangle {
id: square
width: 50
height: main_window.height
color: 'red'
opacity: is_handlebar_inside_snap_area && is_dragging ? 0.5 : 0.9
Drag.active: dragArea.drag.active
MouseArea {
id: dragArea
drag {
target: parent
axis: "XAxis"
minimumX: 0
maximumX: main_window.width - square.width
}
anchors.fill: parent
cursorShape: Qt.SizeAllCursor
onReleased:
{
if (is_handlebar_inside_snap_area)
{
square.x = placeHolderRect.x
}
}
}
}
Rectangle
{
id:placeHolderRect
color: square.color
width: square.width
height: square.height
opacity: 0.3
visible: is_handlebar_inside_snap_area
anchors.horizontalCenter: snap_area.horizontalCenter
}
}
Upvotes: 2