Improve “snap to grid” feel of reservation drag

There was an issue when dragging the reservation too close to the left:
DropArea was no longer receiving onPositionChanged events because the
hotspot was already outside its area.  By default the hotspot is (0, 0),
and was outside the area as soon as the reservation was dragged to day
“-1” of the period.

Changing hotspot to (-width, 0) would only move the problem from the
left to the right side, whe dragging to the day past the last of the
period.

I tried to have the DropArea to have a left margin of -30 days, that way
it would fall way outside the range and continue receiving drag events.
However, ListView’s `clip: true` is not only to limit the visual area—it
also clips the region to receive events—, and i was at square one.

I had to merge all DropArea into a single element, something i should
have to do regardless, and move it as a sibling of the ListView, anchor
to it, and add the negative left margin.  Then, i have to transform
drag’s coordinates from DropArea to ListView.contentItem to know the
correct position of the reservation rectangle relative to its parent.
Using contentItem also obviates the need of having to use scroll
offsets, as this is a Flickable concernt, not of contentItem.

Finally, i changed the Y position of the hotspot to half the rectangle
to give the same distance from the top and from the bottom before
snapping to the previour or next row.
This commit is contained in:
jordi fita mas 2025-01-24 15:30:03 +01:00
parent ab1ebd61b6
commit a9745ec117
2 changed files with 26 additions and 30 deletions

View File

@ -10,8 +10,7 @@ Label {
required property string reservationStatus
Drag.active: dragHandler.active
Drag.hotSpot.x: 0
Drag.hotSpot.y: 0
Drag.hotSpot.y: height / 2
elide: Text.ElideRight
padding: 2
text: holder

View File

@ -99,29 +99,16 @@ Control {
id: verticalScroll
}
delegate: DropArea {
property real contentWidth: ListView.view.contentWidth
required property string name
delegate: TimelineView {
required property TimelineModel timeline
property real viewportWidth: ListView.view.width
property real viewportX: ListView.view.contentX
height: control.rowHeight
width: contentWidth
onPositionChanged: function (drag) {
drag.source.y = y;
drag.source.x = (Math.floor(drag.x / control.dayWidth) + .5) * control.dayWidth;
}
TimelineView {
dayWidth: control.dayWidth
fromDate: control.fromDate
height: parent.height
model: parent.timeline
height: control.rowHeight
model: timeline
toDate: control.toDate
viewportWidth: parent.viewportWidth
viewportX: parent.viewportX
viewportWidth: ListView.view.width
viewportX: ListView.view.contentX
delegate: Reservation {
dragParent: timelineList.contentItem
@ -134,7 +121,6 @@ Control {
palette: control.palette
}
}
}
header: Rectangle {
border.color: Fusion.outline(control.palette)
color: control.palette.base
@ -201,5 +187,16 @@ Control {
}
}
}
DropArea {
anchors.fill: timelineList
anchors.leftMargin: -30 * control.dayWidth
onPositionChanged: function (drag) {
const pos = timelineList.contentItem.mapFromItem(this, drag.x, drag.y);
drag.source.y = (Math.floor(pos.y / control.rowHeight)) * control.rowHeight;
drag.source.x = (Math.floor(pos.x / control.dayWidth) + .5) * control.dayWidth;
}
}
}
}