[vlc-commits] [Git][videolan/vlc][master] 4 commits: qml: enable ability to customize drop indicator in ListViewExt
Felix Paul Kühne (@fkuehne)
gitlab at videolan.org
Fri Sep 13 14:08:12 UTC 2024
Felix Paul Kühne pushed to branch master at VideoLAN / VLC
Commits:
81a50fac by Fatih Uzunoglu at 2024-09-13T13:55:22+00:00
qml: enable ability to customize drop indicator in ListViewExt
In some cases, drop indicator may need to be customized. This
also allows disabling the indicator completely.
The way it works is by instantiating the drop indicator from
the component property once `itemContainsDrag`, which is an
optional property, changes.
- - - - -
43df33c6 by Fatih Uzunoglu at 2024-09-13T13:55:22+00:00
qml: fix invalid property accession in PlaylistDelegate
- - - - -
0174b492 by Fatih Uzunoglu at 2024-09-13T13:55:22+00:00
qml: consolidate `ListViewExt`'s drag and drop functionality over `TableViewExt`
This makes it possible to not re-invent drop indicator positioning, and also
allows rejecting the drag event when drop is not applicable.
In order to reject drag event when not applicable, there needs to be two
drop areas. This has been the case in `PlaylistListView/Delegate` but not
in `TableViewExt/Delegate`. With this patch, I followed the same approach
used in `PlaylistListView` which has a rather proven track record on drag
and drop functionality.
- - - - -
f482c601 by Fatih Uzunoglu at 2024-09-13T13:55:22+00:00
qml: factorize delegate vertical drop area layout in ListViewExt
- - - - -
6 changed files:
- modules/gui/qt/medialibrary/qml/PlaylistMedia.qml
- modules/gui/qt/medialibrary/qml/PlaylistMediaList.qml
- modules/gui/qt/playlist/qml/PlaylistDelegate.qml
- modules/gui/qt/widgets/qml/ListViewExt.qml
- modules/gui/qt/widgets/qml/TableViewDelegate.qml
- modules/gui/qt/widgets/qml/TableViewExt.qml
Changes:
=====================================
modules/gui/qt/medialibrary/qml/PlaylistMedia.qml
=====================================
@@ -98,8 +98,6 @@ MainTableView {
rowHeight: VLCStyle.tableCoverRow_height
- acceptDrop: true
-
sortModel: (availableRowWidth < VLCStyle.colWidth(4)) ? _modelSmall
: _modelMedium
@@ -121,42 +119,6 @@ MainTableView {
onActionForSelection: (selection) => model.addAndPlay( selection )
onItemDoubleClicked: (index, model) => MediaLib.addAndPlay(model.id)
-
- onDropEntered: (delegate, index, drag, before) => {
- if (!root.model || root.model.transactionPending)
- {
- drag.accepted = false
- return
- }
-
- root._dropUpdatePosition(drag, index, delegate, before)
- }
-
- onDropUpdatePosition: (delegate, index, drag, before) => {
- root._dropUpdatePosition(drag, index, delegate, before)
- }
-
- onDropExited: (delegate, index, drag, before) => {
- root.hideLine(delegate)
- }
-
- onDropEvent: (delegate, index, drag, drop, before) => {
- root.applyDrop(drop, index, delegate, before)
- }
-
- //---------------------------------------------------------------------------------------------
- // Connections
- //---------------------------------------------------------------------------------------------
-
- Connections {
- target: root
-
- // NOTE: We want to hide the drop line when scrolling so its position stays relevant.
- function onContentYChanged() {
- hideLine(_item)
- }
- }
-
//---------------------------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------------------------
@@ -176,7 +138,7 @@ MainTableView {
function applyDrop(drop, index, delegate, before) {
if (listView.isDropAcceptableFunc(drop, index + (before ? 0 : 1)) === false) {
- root.hideLine(delegate)
+ drop.accepted = false
return Promise.resolve()
}
@@ -188,14 +150,13 @@ MainTableView {
if (dragItem === item) {
model.move(selectionModel.selectedRows(), destinationIndex)
root.forceActiveFocus()
- root.hideLine(delegate)
// NOTE: Dropping medialibrary content into the playlist.
} else if (Helpers.isValidInstanceOf(item, Widgets.DragItem)) {
return item.getSelectedInputItem()
.then(inputItems => {
model.insert(inputItems, destinationIndex)
})
- .then(() => { root.forceActiveFocus(); root.hideLine(delegate); })
+ .then(() => { root.forceActiveFocus(); })
} else if (drop.hasUrls) {
const urlList = []
for (let url in drop.urls)
@@ -204,48 +165,11 @@ MainTableView {
model.insert(urlList, destinationIndex)
root.forceActiveFocus()
- root.hideLine(delegate)
}
return Promise.resolve()
}
- function _dropUpdatePosition(drag, index, delegate, before) {
- if (listView.isDropAcceptableFunc(drag, index + (before ? 0 : 1)) === false) {
- root.hideLine(delegate)
- return
- }
-
- root.showLine(delegate, before)
- }
-
- //---------------------------------------------------------------------------------------------
- // Drop line
-
- function showLine(item, before)
- {
- // NOTE: We want to avoid calling mapFromItem too many times.
- if (_item === item && _before === before)
- return;
-
- _item = item;
- _before = before;
-
- if (before)
- line.y = view.mapFromItem(item, 0, 0).y;
- else
- line.y = view.mapFromItem(item, 0, item.height).y;
- }
-
- function hideLine(item)
- {
- // NOTE: We want to make sure we're not being called after the 'showLine' function.
- if (_item !== item)
- return;
-
- _item = null;
- }
-
//---------------------------------------------------------------------------------------------
// Childs
//---------------------------------------------------------------------------------------------
=====================================
modules/gui/qt/medialibrary/qml/PlaylistMediaList.qml
=====================================
@@ -408,7 +408,17 @@ MainViewLoader {
header: root.header
- acceptDrop: true
+ listView.isDropAcceptableFunc: function(drag, index) {
+ root._adjustDragAccepted(drag)
+ return drag.accepted
+ }
+
+ listView.acceptDropFunc: function(index, drop) {
+ return new Promise(() => { root._dropAction(drop,
+ listView.itemContainsDrag.index) } )
+ }
+
+ listView.dropIndicator: null
Navigation.parentItem: root
@@ -427,14 +437,6 @@ MainViewLoader {
contextMenu.popup(selectionModel.selectedRows(), globalMousePos)
}
- onDropEntered: (_, _, drag, _) => {
- root._adjustDragAccepted(drag)
- }
-
- onDropEvent: (_, index, _, drop, _) => {
- root._dropAction(drop, index)
- }
-
//-------------------------------------------------------------------------------------
// Childs
=====================================
modules/gui/qt/playlist/qml/PlaylistDelegate.qml
=====================================
@@ -38,23 +38,15 @@ T.Control {
readonly property bool selected : view.selectionModel.selectedIndexesFlat.includes(index)
- readonly property bool topContainsDrag: higherDropArea.containsDrag
+ readonly property bool topContainsDrag: dropAreaLayout.higherDropArea.containsDrag
- readonly property bool bottomContainsDrag: lowerDropArea.containsDrag
+ readonly property bool bottomContainsDrag: dropAreaLayout.lowerDropArea.containsDrag
readonly property bool containsDrag: (topContainsDrag || bottomContainsDrag)
- // drag -> point
- // current drag pos inside the item
- readonly property point drag: {
- if (!containsDrag)
- return Qt.point(0, 0)
-
- const d = topContainsDrag ? higherDropArea : lowerDropArea
- const p = d.drag
- return mapFromItem(d, p.x, p.y)
- }
-
+ readonly property point dragPosition: mapFromItem(dropAreaLayout,
+ dropAreaLayout.dragPosition.x,
+ dropAreaLayout.dragPosition.y)
// Optional
property var contextMenu
@@ -63,10 +55,10 @@ T.Control {
property Item dragItem
// Optional, used to show the drop indicator
- property var isDropAcceptable
+ property alias isDropAcceptable: dropAreaLayout.isDropAcceptable
// Optional, but required to drop a drag
- property var acceptDrop
+ property alias acceptDrop: dropAreaLayout.acceptDrop
// Settings
@@ -325,56 +317,8 @@ T.Control {
}
}
- ColumnLayout {
+ Widgets.ListViewExt.VerticalDropAreaLayout {
+ id: dropAreaLayout
anchors.fill: parent
- spacing: 0
-
- DropArea {
- id: higherDropArea
-
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- onEntered: (drag) => {
- if (!acceptDrop) {
- drag.accept = false
- return
- }
-
- if (isDropAcceptable && !isDropAcceptable(drag, index)) {
- drag.accepted = false
- return
- }
- }
-
- onDropped: (drop) => {
- console.assert(acceptDrop)
- acceptDrop(index, drop)
- }
- }
-
- DropArea {
- id: lowerDropArea
-
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- onEntered: (drag) => {
- if (!acceptDrop) {
- drag.accept = false
- return
- }
-
- if (isDropAcceptable && !isDropAcceptable(drag, index + 1)) {
- drag.accepted = false
- return
- }
- }
-
- onDropped: (drop) => {
- console.assert(acceptDrop)
- acceptDrop(index + 1, drop)
- }
- }
}
}
=====================================
modules/gui/qt/widgets/qml/ListViewExt.qml
=====================================
@@ -18,6 +18,7 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Window
+import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
@@ -106,6 +107,83 @@ ListView {
footer: !!root.acceptDropFunc ? footerDragAccessoryComponent : null
+ onItemContainsDragChanged: {
+ if (!dropIndicatorItem && dropIndicator)
+ dropIndicatorItem = dropIndicator.createObject(this)
+ }
+
+ component VerticalDropAreaLayout : ColumnLayout {
+ spacing: 0
+
+ property alias higherDropArea: higherDropArea
+ property alias lowerDropArea: lowerDropArea
+
+ property var isDropAcceptable
+ property var acceptDrop
+
+ readonly property point dragPosition: {
+ let area = null
+
+ if (higherDropArea.containsDrag)
+ area = higherDropArea
+ else if (lowerDropArea.containsDrag)
+ area = lowerDropArea
+ else
+ return Qt.point(0, 0)
+
+ const drag = area.drag
+ return Qt.point(drag.x, drag.y)
+ }
+
+ DropArea {
+ id: higherDropArea
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ onEntered: (drag) => {
+ if (!acceptDrop) {
+ drag.accepted = false
+ return
+ }
+
+ if (isDropAcceptable && !isDropAcceptable(drag, index)) {
+ drag.accepted = false
+ return
+ }
+ }
+
+ onDropped: (drop) => {
+ console.assert(acceptDrop)
+ acceptDrop(index, drop)
+ }
+ }
+
+ DropArea {
+ id: lowerDropArea
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ onEntered: (drag) => {
+ if (!acceptDrop) {
+ drag.accepted = false
+ return
+ }
+
+ if (isDropAcceptable && !isDropAcceptable(drag, index + 1)) {
+ drag.accepted = false
+ return
+ }
+ }
+
+ onDropped: (drop) => {
+ console.assert(acceptDrop)
+ acceptDrop(index + 1, drop)
+ }
+ }
+ }
+
Component {
id: footerDragAccessoryComponent
@@ -135,7 +213,7 @@ ListView {
}
}
- property alias drag: dropArea.drag
+ property alias dragPosition: dropArea.drag
Rectangle {
id: firstItemIndicator
@@ -424,7 +502,7 @@ ListView {
dragging: root.itemContainsDrag !== null
dragPosProvider: function () {
const source = root.itemContainsDrag
- const point = source.drag
+ const point = source.dragPosition
return root.mapFromItem(source, point.x, point.y)
}
}
@@ -495,9 +573,7 @@ ListView {
}
}
- Rectangle {
- id: dropIndicator
-
+ property Component dropIndicator: Rectangle {
parent: {
const item = root.itemContainsDrag
if (!item || item.topContainsDrag === undefined || item.bottomContainsDrag === undefined)
@@ -528,6 +604,8 @@ ListView {
color: theme.accent
}
+ property Item dropIndicatorItem
+
// FIXME: We probably need to upgrade these RoundButton(s) eventually. And we probably need
// to have some kind of animation when switching pages.
=====================================
modules/gui/qt/widgets/qml/TableViewDelegate.qml
=====================================
@@ -34,15 +34,24 @@ T.Control {
required property var sortModel
required property bool selected
required property Widgets.DragItem dragItem
- required property bool acceptDrop
- readonly property bool dragActive: dragHandler.active
- property alias containsDrag: dropArea.containsDrag
- property alias drag: dropArea.drag
+ readonly property bool topContainsDrag: dropAreaLayout.higherDropArea.containsDrag
+ readonly property bool bottomContainsDrag: dropAreaLayout.lowerDropArea.containsDrag
+ readonly property bool containsDrag: (topContainsDrag || bottomContainsDrag)
required property real fixedColumnWidth
required property real weightedColumnWidth
+ readonly property point dragPosition: mapFromItem(dropAreaLayout,
+ dropAreaLayout.dragPosition.x,
+ dropAreaLayout.dragPosition.y)
+
+ // Optional, used to show the drop indicator
+ property alias isDropAcceptable: dropAreaLayout.isDropAcceptable
+
+ // Optional, but required to drop a drag
+ property alias acceptDrop: dropAreaLayout.acceptDrop
+
property int _modifiersOnLastPress: Qt.NoModifier
signal contextMenuButtonClicked(Item menuParent, var menuModel, point globalMousePos)
@@ -51,11 +60,6 @@ T.Control {
signal selectAndFocus(int modifiers, int focusReason)
- signal dropEntered(var drag, bool before)
- signal dropUpdatePosition(var drag, bool before)
- signal dropExited(var drag, bool before)
- signal dropEvent(var drag, var drop, bool before)
-
property Component defaultDelegate: TableRowDelegate {
id: defaultDelId
Widgets.TextAutoScroller {
@@ -82,7 +86,7 @@ T.Control {
hoverEnabled: true
- ListView.delayRemove: dragActive
+ ListView.delayRemove: dragHandler.active
Component.onCompleted: {
Keys.menuPressed.connect(contextButton.clicked)
@@ -282,24 +286,8 @@ T.Control {
}
}
- DropArea {
- id: dropArea
-
- enabled: delegate.acceptDrop
-
+ Widgets.ListViewExt.VerticalDropAreaLayout {
+ id: dropAreaLayout
anchors.fill: parent
-
- function isBefore(drag) {
- return drag.y < height/2
- }
-
- onEntered: (drag) => { delegate.dropEntered(drag, isBefore(drag)) }
-
- onPositionChanged: (drag) => { delegate.dropUpdatePosition(drag, isBefore(drag)) }
-
- onExited:delegate.dropExited(drag, isBefore(drag))
-
- onDropped: (drop) => { delegate.dropEvent(drag, drop, isBefore(drag)) }
-
}
}
=====================================
modules/gui/qt/widgets/qml/TableViewExt.qml
=====================================
@@ -99,7 +99,6 @@ FocusScope {
property real availableRowWidth: 0
property Widgets.DragItem dragItem: null
- property bool acceptDrop: false
// Private
@@ -162,11 +161,6 @@ FocusScope {
signal rightClick(Item menuParent, var menuModel, point globalMousePos)
signal itemDoubleClicked(var index, var model)
- signal dropUpdatePosition(Item delegate, int index, var drag, bool before)
- signal dropEntered(Item delegate, int index, var drag, bool before)
- signal dropExited(Item delegate, int index, var drag, bool before)
- signal dropEvent(Item delegate, int index, var drag, var drop, bool before)
-
// Events
Component.onCompleted: {
@@ -413,8 +407,6 @@ FocusScope {
selected: selectionModel.selectedIndexesFlat.includes(index)
- acceptDrop: root.acceptDrop
-
onContextMenuButtonClicked: (menuParent, menuModel, globalMousePos) => {
root.contextMenuButtonClicked(menuParent, menuModel, globalMousePos)
}
@@ -425,18 +417,8 @@ FocusScope {
root.itemDoubleClicked(index, model)
}
- onDropEntered: (drag, before) => {
- root.dropEntered(tableDelegate, index, drag, before)
- }
- onDropUpdatePosition: (drag, before) => {
- root.dropUpdatePosition(tableDelegate, index, drag, before)
- }
- onDropExited: (drag, before) => {
- root.dropExited(tableDelegate, index, drag, before)
- }
- onDropEvent: (drag, drop, before) => {
- root.dropEvent(tableDelegate, index, drag, drop, before)
- }
+ isDropAcceptable: view.isDropAcceptableFunc
+ acceptDrop: view.acceptDropFunc
onSelectAndFocus: (modifiers, focusReason) => {
selectionModel.updateSelection(modifiers, view.currentIndex, index)
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/3855b4610654aa4b926061e0e9d66f64566ca6f4...f482c6017586b5242ba6422d3b6cc43c3d3b11ac
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/3855b4610654aa4b926061e0e9d66f64566ca6f4...f482c6017586b5242ba6422d3b6cc43c3d3b11ac
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list