filemanager/qml/FolderListView.qml

464 lines
14 KiB
QML
Raw Normal View History

2021-03-16 00:02:20 -07:00
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
2021-04-09 07:49:19 -07:00
import FishUI 1.0 as FishUI
2021-03-29 01:51:34 -07:00
import Cutefish.FileManager 1.0
2021-03-16 00:02:20 -07:00
ListView {
id: control
2021-03-29 01:51:34 -07:00
property Item rubberBand: null
property Item hoveredItem: null
property Item pressedItem: null
property int verticalDropHitscanOffset: 0
property int pressX: -1
property int pressY: -1
property int dragX: -1
property int dragY: -1
property bool ctrlPressed: false
property bool shiftPressed: false
2021-03-16 00:02:20 -07:00
2021-03-29 01:51:34 -07:00
property int previouslySelectedItemIndex: -1
property variant cPress: null
property Item editor: null
property int anchorIndex: 0
2021-04-12 19:46:20 -07:00
property var itemHeight: FishUI.Units.fontMetrics.height * 2 + FishUI.Units.smallSpacing
2021-04-04 08:38:01 -07:00
property variant cachedRectangleSelection: null
2021-03-29 01:51:34 -07:00
signal keyPress(var event)
currentIndex: -1
2021-03-16 00:02:20 -07:00
clip: true
ScrollBar.vertical: ScrollBar { }
boundsBehavior: Flickable.StopAtBounds
FishUI.WheelHandler {
target: control
}
2021-03-16 00:02:20 -07:00
2021-04-04 13:06:24 -07:00
function rename() {
if (currentIndex !== -1) {
var renameAction = control.model.action("rename")
if (renameAction && !renameAction.enabled)
return
if (!control.editor)
control.editor = editorComponent.createObject(control)
control.editor.targetItem = control.currentItem
}
}
function cancelRename() {
if (control.editor) {
control.editor.cancel()
control.editor.destroy()
control.editor = null
}
}
function reset() {
currentIndex = -1
anchorIndex = 0
previouslySelectedItemIndex = -1
cancelRename()
hoveredItem = null
pressedItem = null
cPress = null
}
2021-03-16 00:02:20 -07:00
highlightMoveDuration: 0
2021-04-04 13:06:24 -07:00
Keys.enabled: true
2021-03-29 01:51:34 -07:00
Keys.onPressed: {
if (event.key === Qt.Key_Control) {
ctrlPressed = true
} else if (event.key === Qt.Key_Shift) {
shiftPressed = true
if (currentIndex != -1)
anchorIndex = currentIndex
}
control.keyPress(event)
}
2021-04-04 13:06:24 -07:00
2021-03-29 01:51:34 -07:00
Keys.onReleased: {
if (event.key === Qt.Key_Control) {
ctrlPressed = false
} else if (event.key === Qt.Key_Shift) {
shiftPressed = false
anchorIndex = 0
}
}
2021-04-04 13:06:24 -07:00
Keys.onEscapePressed: {
if (!editor || !editor.targetItem) {
previouslySelectedItemIndex = -1
dirModel.clearSelection()
2021-04-04 13:06:24 -07:00
event.accepted = false
}
}
Keys.onUpPressed: {
if (!editor || !editor.targetItem) {
var newIndex = currentIndex
newIndex--;
if (newIndex < 0)
newIndex = 0
currentIndex = newIndex
updateSelection(event.modifiers)
}
}
Keys.onDownPressed: {
if (!editor || !editor.targetItem) {
var newIndex = currentIndex
newIndex++
if (newIndex >= control.count)
return
currentIndex = newIndex
updateSelection(event.modifiers)
}
}
2021-04-04 08:38:01 -07:00
onCachedRectangleSelectionChanged: {
if (cachedRectangleSelection === null)
return
if (cachedRectangleSelection.length)
control.currentIndex[0]
dirModel.updateSelection(cachedRectangleSelection, control.ctrlPressed)
2021-04-04 08:38:01 -07:00
}
2021-03-29 01:51:34 -07:00
onContentXChanged: {
cancelRename()
}
onContentYChanged: {
cancelRename()
}
onPressXChanged: {
cPress = mapToItem(control.contentItem, pressX, pressY)
}
onPressYChanged: {
cPress = mapToItem(control.contentItem, pressX, pressY)
}
2021-03-16 00:02:20 -07:00
MouseArea {
2021-03-29 01:51:34 -07:00
id: _mouseArea
2021-03-16 00:02:20 -07:00
anchors.fill: parent
propagateComposedEvents: true
2021-03-29 01:51:34 -07:00
preventStealing: true
acceptedButtons: Qt.RightButton | Qt.LeftButton
hoverEnabled: true
enabled: true
z: -1
onDoubleClicked: {
if (mouse.button === Qt.LeftButton && control.pressedItem)
dirModel.openSelected()
2021-03-29 01:51:34 -07:00
}
onPressed: {
control.forceActiveFocus()
if (control.editor && childAt(mouse.x, mouse.y) !== control.editor)
control.editor.commit()
if (mouse.source === Qt.MouseEventSynthesizedByQt) {
var index = control.indexAt(mouse.x, mouse.y + control.contentY)
var indexItem = control.itemAtIndex(index)
if (indexItem && indexItem.iconArea) {
control.currentIndex = index
hoveredItem = indexItem
} else {
hoveredItem = null
}
}
pressX = mouse.x
pressY = mouse.y
if (!hoveredItem || hoveredItem.blank) {
if (!control.ctrlPressed) {
control.currentIndex = -1
control.previouslySelectedItemIndex = -1
dirModel.clearSelection()
2021-03-29 01:51:34 -07:00
}
if (mouse.buttons & Qt.RightButton) {
clearPressState()
dirModel.openContextMenu(null, mouse.modifiers)
2021-03-29 01:51:34 -07:00
mouse.accepted = true
}
} else {
pressedItem = hoveredItem
if (control.shiftPressed && control.currentIndex !== -1) {
dirModel.setRangeSelected(control.anchorIndex, hoveredItem.index)
2021-03-29 01:51:34 -07:00
} else {
if (!control.ctrlPressed && !dirModel.isSelected(hoveredItem.index)) {
2021-03-29 01:51:34 -07:00
previouslySelectedItemIndex = -1
dirModel.clearSelection()
2021-03-29 01:51:34 -07:00
}
2021-04-12 19:17:23 -07:00
if (control.ctrlPressed) {
dirModel.toggleSelected(hoveredItem.index)
2021-04-12 19:17:23 -07:00
} else {
dirModel.setSelected(hoveredItem.index)
2021-04-12 19:17:23 -07:00
}
2021-03-29 01:51:34 -07:00
}
control.currentIndex = hoveredItem.index
if (mouse.buttons & Qt.RightButton) {
clearPressState()
dirModel.openContextMenu(null, mouse.modifiers)
2021-03-29 01:51:34 -07:00
mouse.accepted = true
}
}
}
onClicked: {
clearPressState()
if (!hoveredItem || hoveredItem.blank || control.currentIndex === -1 || control.ctrlPressed
|| control.shiftPressed) {
return
}
// TODO: rename
}
onPositionChanged: {
control.ctrlPressed = (mouse.modifiers & Qt.ControlModifier)
control.shiftPressed = (mouse.modifiers & Qt.ShiftModifier)
var cPos = mapToItem(control.contentItem, mouse.x, mouse.y)
2021-04-12 19:46:20 -07:00
var item = control.itemAt(mouse.x - control.leftMargin, mouse.y + control.contentY)
2021-03-29 01:51:34 -07:00
var leftEdge = Math.min(control.contentX, control.originX)
if (!item || item.blank) {
if (control.hoveredItem) {
control.hoveredItem = null
}
} else {
control.hoveredItem = item
}
// TODO: autoscroll
if (control.rubberBand) {
var rB = control.rubberBand
if (cPos.x < cPress.x) {
rB.x = Math.max(leftEdge, cPos.x)
rB.width = Math.abs(rB.x - cPress.x)
} else {
rB.x = cPress.x
var ceil = Math.max(control.width, control.contentItem.width) + leftEdge
rB.width = Math.min(ceil - rB.x, Math.abs(rB.x - cPos.x))
}
if (cPos.y < cPress.y) {
rB.y = Math.max(0, cPos.y)
rB.height = Math.abs(rB.y - cPress.y)
} else {
rB.y = cPress.y
var ceilValue = Math.max(control.height, control.contentItem.height)
rB.height = Math.min(ceilValue - rB.y, Math.abs(rB.y - cPos.y))
}
// Ensure rubberband is at least 1px in size or else it will become
// invisible and not match any items.
rB.width = Math.max(1, rB.width)
rB.height = Math.max(1, rB.height)
control.rectangleSelect(rB.x, rB.y, rB.width, rB.height)
return
}
// Drag
if (pressX != -1) {
if (pressedItem != null && dirModel.isSelected(pressedItem.index)) {
2021-03-29 01:51:34 -07:00
control.dragX = mouse.x
control.dragY = mouse.y
control.verticalDropHitscanOffset = pressedItem.y + (pressedItem.height / 2)
dirModel.dragSelected(mouse.x, mouse.y)
2021-03-29 01:51:34 -07:00
control.dragX = -1
control.dragY = -1
clearPressState()
} else {
2021-04-04 13:06:24 -07:00
if (control.editor && control.editor.targetItem)
return;
dirModel.pinSelection()
2021-03-29 01:51:34 -07:00
control.rubberBand = rubberBandObject.createObject(control.contentItem, {x: cPress.x, y: cPress.y})
control.interactive = false
}
}
}
onContainsMouseChanged: {
if (!containsMouse && !control.rubberBand) {
clearPressState()
if (control.hoveredItem) {
control.hoveredItem = null
}
}
}
2021-04-13 10:09:01 -07:00
onReleased: {
if (pressedItem != null &&
!control.rubberBand &&
2021-04-14 08:40:22 -07:00
!control.shiftPressed &&
!control.ctrlPressed &&
2021-04-13 10:09:01 -07:00
!dirModel.dragging) {
dirModel.clearSelection()
dirModel.setSelected(pressedItem.index)
}
pressCanceled()
}
2021-03-29 01:51:34 -07:00
onCanceled: pressCanceled()
}
function pressCanceled() {
if (control.rubberBand) {
control.rubberBand.close()
control.rubberBand = null
control.interactive = true
2021-04-04 08:38:01 -07:00
control.cachedRectangleSelection = null
dirModel.unpinSelection()
2021-03-29 01:51:34 -07:00
}
clearPressState()
// control.cancelAutoscroll()
}
function clearPressState() {
pressedItem = null
pressX = -1
pressY = -1
}
function rectangleSelect(x, y, width, height) {
2021-04-04 08:38:01 -07:00
var indexes = []
for (var i = y; i <= y + height; i += 10) {
2021-04-12 19:46:20 -07:00
const index = control.indexAt(control.leftMargin, i)
if(!indexes.includes(index) && index > -1 && index < control.count)
2021-04-04 08:38:01 -07:00
indexes.push(index)
}
cachedRectangleSelection = indexes
2021-03-29 01:51:34 -07:00
}
function updateSelection(modifier) {
if (modifier & Qt.ShiftModifier) {
dirModel.setRangeSelected(anchorIndex, currentIndex)
2021-03-29 01:51:34 -07:00
} else {
dirModel.clearSelection()
dirModel.setSelected(currentIndex)
2021-03-29 01:51:34 -07:00
if (currentIndex == -1)
previouslySelectedItemIndex = -1
previouslySelectedItemIndex = currentIndex
}
}
Component {
id: editorComponent
2021-04-04 13:06:24 -07:00
TextField {
2021-03-29 01:51:34 -07:00
id: _editor
visible: false
wrapMode: Text.NoWrap
verticalAlignment: TextEdit.AlignVCenter
2021-04-04 13:06:24 -07:00
z: 999
2021-03-29 01:51:34 -07:00
property Item targetItem: null
onTargetItemChanged: {
if (targetItem != null) {
2021-04-01 01:05:15 -07:00
var pos = control.mapFromItem(targetItem, targetItem.labelArea.x, targetItem.labelArea.y)
2021-04-01 07:16:42 -07:00
width = targetItem.labelArea.width
2021-04-09 07:49:19 -07:00
height = FishUI.Units.fontMetrics.height + FishUI.Units.largeSpacing * 2
2021-04-01 01:05:15 -07:00
x = control.mapFromItem(targetItem.labelArea, 0, 0).x
2021-04-04 13:06:24 -07:00
y = pos.y + (targetItem.height - height) / 2
2021-04-01 01:05:15 -07:00
text = targetItem.labelArea.text
targetItem.labelArea.visible = false
targetItem.labelArea2.visible = false
_editor.select(0, dirModel.fileExtensionBoundary(targetItem.index))
2021-03-29 01:51:34 -07:00
visible = true
2021-04-04 13:06:24 -07:00
control.interactive = false
2021-03-29 01:51:34 -07:00
} else {
x: 0
y: 0
visible = false
2021-04-04 13:06:24 -07:00
control.interactive = true
2021-03-29 01:51:34 -07:00
}
}
2021-04-04 13:06:24 -07:00
onVisibleChanged: {
if (visible)
_editor.forceActiveFocus()
else
control.forceActiveFocus()
}
2021-03-29 01:51:34 -07:00
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Return:
case Qt.Key_Enter:
commit()
2021-04-04 13:06:24 -07:00
event.accepted = true
2021-03-29 01:51:34 -07:00
break
case Qt.Key_Escape:
2021-04-01 01:05:15 -07:00
cancel()
2021-04-04 13:06:24 -07:00
event.accepted = true
2021-03-29 01:51:34 -07:00
break
}
}
function commit() {
if (targetItem) {
2021-04-01 01:05:15 -07:00
targetItem.labelArea.visible = true
targetItem.labelArea2.visible = true
dirModel.rename(targetItem.index, text)
2021-03-29 01:51:34 -07:00
control.currentIndex = targetItem.index
targetItem = null
2021-04-04 13:06:24 -07:00
control.editor.destroy()
2021-03-29 01:51:34 -07:00
}
}
2021-04-01 01:05:15 -07:00
function cancel() {
if (targetItem) {
targetItem.labelArea.visible = true
targetItem.labelArea2.visible = true
2021-04-04 13:06:24 -07:00
control.currentIndex = targetItem.index
2021-04-01 01:05:15 -07:00
targetItem = null
2021-04-04 13:06:24 -07:00
control.editor.destroy()
2021-04-01 01:05:15 -07:00
}
}
2021-03-29 01:51:34 -07:00
}
2021-03-16 00:02:20 -07:00
}
}