[vlc-commits] [Git][videolan/vlc][master] 4 commits: qml: document required properties from delegate of ExpandGridView
Steve Lhomme (@robUx4)
gitlab at videolan.org
Fri Feb 16 15:28:12 UTC 2024
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
231dcc39 by Prince Gupta at 2024-02-16T14:47:14+00:00
qml: document required properties from delegate of ExpandGridView
- - - - -
4dac3a17 by Prince Gupta at 2024-02-16T14:47:14+00:00
qml: minor refactor code in positioning item in ExpandGridView
- - - - -
5418ed66 by Prince Gupta at 2024-02-16T14:47:14+00:00
qml: implement 'delayRemove' for delegates of ExpandGridView
- - - - -
e215f686 by Prince Gupta at 2024-02-16T14:47:14+00:00
qml: implement 'reuseItems' for ExpandGridView
- - - - -
1 changed file:
- modules/gui/qt/widgets/qml/ExpandGridView.qml
Changes:
=====================================
modules/gui/qt/widgets/qml/ExpandGridView.qml
=====================================
@@ -57,6 +57,12 @@ FocusScope {
readonly property int rowHeight: cellHeight + verticalSpacing
+ // This property enables you to reuse items that are instantiated for
+ // different indexes when particular index goes out of view
+ // not setting may result in large performance penalty
+ // default is true
+ property bool reuseItems: true
+
property int rowX: 0
property int horizontalSpacing: VLCStyle.column_spacing
property int verticalSpacing: VLCStyle.column_spacing
@@ -94,12 +100,33 @@ FocusScope {
property int _currentFocusReason: Qt.OtherFocusReason
- //delegate to display the extended item
- property Component delegate: Item{}
+ // The delegate provides a template defining each item instantiated by the view.
+ // 'delegate' must have following properties defined -
+ // 'var model'
+ // - set by ExpandGridView, this defines model data associated with item
+ // index data can be accesses by the model roles
+ // 'int index'
+ // - set by ExpandGridView, this defines the index to which this delegate
+ // is associated to
+ // 'bool selected'
+ // - set by ExpandGridView, this defines if the associated index is selected
+ // in selectionModel
+ //
+ // optional properties -
+ // 'bool delayRemove'
+ // - if defined and set, item will not be removed when it goes out of view
+ // ExpandGridView will never modify this value
+ //
+ property Component delegate: Item {
+ property var model: null
+ property int index: - 1
+ property bool selected: false
+ }
property var _idChildrenList: []
property var _unusedItemList: []
property var _currentRange: [0,0]
+ property var _delayedChildrenMap: ({})
// Aliases
@@ -175,6 +202,13 @@ FocusScope {
flickable.layout(true)
}
+ onReuseItemsChanged: {
+ if (!reuseItems) {
+ _unusedItemList.forEach((item) => { item.destroy() })
+ _unusedItemList = []
+ }
+ }
+
// Keys
Keys.onPressed: (event) => {
@@ -255,6 +289,9 @@ FocusScope {
const iMin = topLeft.row
const iMax = bottomRight.row + 1 // [] => [)
const f_l = _currentRange
+
+ _refreshDelayedChildData(iMin, iMax)
+
if (iMin < f_l[1] && f_l[0] < iMax) {
_refreshData(iMin, iMax)
}
@@ -283,9 +320,15 @@ FocusScope {
function _updateSelectedRange(topLeft, bottomRight, select) {
let iMin = topLeft.row
let iMax = bottomRight.row + 1 // [] => [)
+
+ // delayed children can be out of currentRange
+ _updateDelayedChildSelected(iMin, iMax, select)
+
if (iMin < root._currentRange[1] && root._currentRange[0] < iMax) {
+ // only update item in the view
iMin = Math.max(iMin, root._currentRange[0])
iMax = Math.min(iMax, root._currentRange[1])
+
for (let j = iMin; j < iMax; j++) {
const item = root._getItem(j)
console.assert(item)
@@ -511,16 +554,28 @@ FocusScope {
return rowCol[0] % 2 + 2 * (rowCol[1] % 2)
}
- function _repositionItem(id, x, y) {
- const item = _getItem(id)
- console.assert(item !== undefined, "wrong child: " + id)
-
+ function _updatePosition(id, item, x, y) {
//theses properties are always defined in Item
item.x = x
item.y = y
item.z = _indexToZ(id)
+
+ // update required property (do we need this??)
item.selected = selectionModel.isSelected(id)
+ }
+
+ function _repositionItem(id, x, y) {
+ const item = _getItem(id)
+ console.assert(item !== undefined, "wrong child: " + id)
+ _updatePosition(id, item, x, y)
+ return item
+ }
+
+ function _repositionDelayedItem(id, x, y) {
+ const item = _delayedChildrenMap[id]
+
+ _updatePosition(id, item, x, y)
return item
}
@@ -558,17 +613,63 @@ FocusScope {
return item
}
+ function _takeDelayedChild(id) {
+ const item = _delayedChildrenMap[id]
+ console.assert(typeof item !== "undefined")
+ delete _delayedChildrenMap[id]
+ return item
+ }
+
+ function _shouldDelayRemove(item) {
+ return Helpers.get(item, "delayRemove", false)
+ }
+
+ function _delayRemove(id, item) {
+ _delayedChildrenMap[id] = item
+
+ item.delayRemoveChanged.connect(() => {
+ if (id in _delayedChildrenMap && !item.delayRemove) {
+ const removed = _takeDelayedChild(id)
+ console.assert(removed === item)
+ item.destroy()
+ }
+ })
+ }
+
+ function _refreshDelayedChildData(iMin, iMax) {
+ for (let i = iMin; i < iMax; ++i) {
+ if (!(i in _delayedChildrenMap))
+ continue
+
+ const item = _delayedChildrenMap[i]
+ item.model = model.getDataAt(i)
+ }
+ }
+
+ function _updateDelayedChildSelected(iMin, iMax, select) {
+ for (let i = iMin; i < iMax; ++i) {
+ if (!(i in _delayedChildrenMap))
+ continue
+
+ const item = _delayedChildrenMap[i]
+ item.selected = select
+ }
+ }
+
function _setupChild(id, ydelta) {
const pos = getItemPos(id)
+ pos[1] += ydelta
let item;
if (_containsItem(id))
- item = _repositionItem(id, pos[0], pos[1] + ydelta)
- else if (_unusedItemList.length > 0)
- item = _recycleItem(id, pos[0], pos[1] + ydelta)
+ item = _repositionItem(id, pos[0], pos[1])
+ else if (id in _delayedChildrenMap)
+ item = _repositionDelayedItem(id, pos[0], pos[1])
+ else if (_unusedItemList.length > 0) // if reuseItems is false, _unusedItemList is always empty
+ item = _recycleItem(id, pos[0], pos[1])
else
- item = _createItem(id, pos[0], pos[1] + ydelta)
+ item = _createItem(id, pos[0], pos[1])
// NOTE: This makes sure we have the proper focus reason on the GridItem.
if (activeFocus && currentIndex === item.index && expandIndex === -1)
@@ -749,8 +850,13 @@ FocusScope {
function _updateChildrenMap(first, last) {
if (first >= last) {
- root._idChildrenList.forEach(function(item) { item.visible = false; })
- root._unusedItemList = root._idChildrenList
+ if (root.reuseItems) {
+ root._idChildrenList.forEach((item) => { item.visible = false; })
+ root._unusedItemList = root._idChildrenList
+ } else {
+ root._idChildrenList.forEach((item) => { item.destroy() })
+ }
+
root._idChildrenList = []
root._currentRange = [0, 0]
return
@@ -760,16 +866,31 @@ FocusScope {
const newList = new Array(last - first)
+ // move items from currentRange still in view
for (let i = overlapped[0]; i < overlapped[1]; ++i) {
newList[i - first] = root._getItem(i)
root._setItem(i, undefined)
}
+ for (let id in _delayedChildrenMap) {
+ if (id >= first && id < last) {
+ newList[id - first] = _takeDelayedChild(id)
+ }
+ }
+
+ // handle item from current range which are not in view
for (let i = root._currentRange[0]; i < root._currentRange[1]; ++i) {
const item = root._getItem(i)
if (typeof item !== "undefined") {
- item.visible = false
- root._unusedItemList.push(item)
+ if (_shouldDelayRemove(item)) {
+ _delayRemove(i, item)
+ } else if (root.reuseItems) {
+ item.visible = false
+ root._unusedItemList.push(item)
+ } else {
+ item.destroy()
+ }
+
// root._setItem(i, undefined) // not needed the list will be reset following this loop
}
}
@@ -812,6 +933,26 @@ FocusScope {
// Place the delegates after the expandItem
_setupIndexes(forceRelayout, [topGridEndId, lastId], root._expandItemVerticalSpace)
+
+ // handle delayedRemoveChildren
+ if (forceRelayout) {
+ for (let id in _delayedChildrenMap) {
+ // check invariant: delayedRemove child must be reused when they come in view
+ console.assert((id < root._currentRange[0]) || (id >= root._currentRange[1]))
+
+ if (id >= root._count) {
+ // index is no longer valid
+ const item = _takeDelayedChild(id)
+ item.destroy()
+ } else {
+ const yDelta = (id >= topGridEndId) ? root._expandItemVerticalSpace : 0
+ _setupChild(id, yDelta)
+ }
+ }
+ }
+
+ if (!root.reuseItems) // check invariant: correct cleanup if reuseItems is not set
+ console.assert(_unusedItemList.length == 0)
}
Connections {
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f95c9c6aa692f8cb9ec56a637795d0cd65dc5ee4...e215f68602b9fb90d2f919db0005a63374110299
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f95c9c6aa692f8cb9ec56a637795d0cd65dc5ee4...e215f68602b9fb90d2f919db0005a63374110299
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