2021-05-24 04:01:26 -07:00
|
|
|
/*
|
2021-06-01 22:25:04 -07:00
|
|
|
* Copyright (C) 2021 revenmartin <revenmartin@gmail.com>
|
|
|
|
* Copyright (C) 2014-2015 by Eike Hein <hein@kde.org>
|
2021-05-24 04:01:26 -07:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2022-03-28 00:35:48 -07:00
|
|
|
import QtQuick 2.15
|
|
|
|
import QtQuick.Controls 2.15
|
|
|
|
import QtQuick.Layouts 1.15
|
2021-03-29 01:51:34 -07:00
|
|
|
|
|
|
|
import Cutefish.FileManager 1.0
|
2021-11-03 10:35:09 -07:00
|
|
|
import Cutefish.DragDrop 1.0 as DragDrop
|
2021-04-09 07:49:19 -07:00
|
|
|
import FishUI 1.0 as FishUI
|
2021-03-29 01:51:34 -07:00
|
|
|
|
|
|
|
GridView {
|
|
|
|
id: control
|
|
|
|
|
2021-12-21 06:35:56 -08:00
|
|
|
objectName: "FolderGridView"
|
|
|
|
|
2021-03-30 09:20:52 -07:00
|
|
|
property bool isDesktopView: false
|
|
|
|
|
2021-03-29 01:51:34 -07:00
|
|
|
property Item rubberBand: null
|
|
|
|
property Item hoveredItem: null
|
|
|
|
property Item pressedItem: null
|
|
|
|
|
2021-04-05 00:21:39 -07:00
|
|
|
property alias positions: positioner.positions
|
|
|
|
property alias positioner: positioner
|
|
|
|
|
2021-03-29 01:51:34 -07:00
|
|
|
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
|
|
|
|
|
|
|
|
property variant cPress: null
|
|
|
|
property Item editor: null
|
|
|
|
property int anchorIndex: 0
|
|
|
|
|
2021-03-30 09:20:52 -07:00
|
|
|
property var iconSize: settings.gridIconSize
|
2021-03-30 23:01:22 -07:00
|
|
|
property var maximumIconSize: settings.maximumIconSize
|
2021-09-15 00:46:38 -07:00
|
|
|
property var minimumIconSize: 22 //settings.minimumIconSize
|
2021-03-29 01:51:34 -07:00
|
|
|
|
|
|
|
property variant cachedRectangleSelection: null
|
|
|
|
|
|
|
|
property bool scrollLeft: false
|
|
|
|
property bool scrollRight: false
|
|
|
|
property bool scrollUp: false
|
|
|
|
property bool scrollDown: false
|
|
|
|
|
|
|
|
signal keyPress(var event)
|
2024-01-23 12:43:32 -08:00
|
|
|
signal backPress()
|
|
|
|
signal forwardPress()
|
2021-03-29 01:51:34 -07:00
|
|
|
|
2021-09-05 14:39:56 -07:00
|
|
|
cacheBuffer: Math.max(0, control.height * 1.5)
|
2022-03-28 00:35:48 -07:00
|
|
|
reuseItems: true
|
2021-06-22 21:37:42 -07:00
|
|
|
|
2021-05-09 19:22:33 -07:00
|
|
|
onIconSizeChanged: {
|
|
|
|
// 图标大小改变时需要重置状态,否则选中定位不准确
|
|
|
|
positioner.reset()
|
|
|
|
}
|
|
|
|
|
2021-10-27 05:02:58 -07:00
|
|
|
onCountChanged: {
|
|
|
|
positioner.reset()
|
|
|
|
}
|
|
|
|
|
2021-04-05 00:21:39 -07:00
|
|
|
function effectiveNavDirection(flow, layoutDirection, direction) {
|
|
|
|
if (direction === Qt.LeftArrow) {
|
|
|
|
if (flow === GridView.FlowLeftToRight) {
|
|
|
|
if (layoutDirection === Qt.LeftToRight) {
|
|
|
|
return Qt.LeftArrow;
|
|
|
|
} else {
|
|
|
|
return Qt.RightArrow;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (layoutDirection === Qt.LeftToRight) {
|
|
|
|
return Qt.UpArrow;
|
|
|
|
} else {
|
|
|
|
return Qt.DownArrow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (direction === Qt.RightArrow) {
|
|
|
|
if (flow === GridView.FlowLeftToRight) {
|
|
|
|
if (layoutDirection === Qt.LeftToRight) {
|
|
|
|
return Qt.RightArrow;
|
|
|
|
} else {
|
|
|
|
return Qt.LeftArrow;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (layoutDirection === Qt.LeftToRight) {
|
|
|
|
return Qt.DownArrow;
|
|
|
|
} else {
|
|
|
|
return Qt.UpArrow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (direction === Qt.UpArrow) {
|
|
|
|
if (flow === GridView.FlowLeftToRight) {
|
|
|
|
return Qt.UpArrow;
|
|
|
|
} else {
|
|
|
|
return Qt.LeftArrow;
|
|
|
|
}
|
|
|
|
} else if (direction === Qt.DownArrow) {
|
|
|
|
if (flow === GridView.FlowLeftToRight) {
|
|
|
|
return Qt.DownArrow;
|
|
|
|
} else {
|
|
|
|
return Qt.RightArrow
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-30 18:22:32 -07:00
|
|
|
function rename() {
|
|
|
|
if (control.currentIndex != -1) {
|
|
|
|
var renameAction = control.model.action("rename")
|
|
|
|
if (renameAction && !renameAction.enabled)
|
|
|
|
return
|
|
|
|
|
|
|
|
if (!editor)
|
|
|
|
editor = editorComponent.createObject(control)
|
|
|
|
|
|
|
|
editor.targetItem = control.currentItem
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function cancelRename() {
|
|
|
|
if (editor) {
|
2021-04-01 01:05:15 -07:00
|
|
|
editor.cancel()
|
2021-03-30 18:22:32 -07:00
|
|
|
editor.targetItem = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-04 13:06:24 -07:00
|
|
|
function reset() {
|
|
|
|
currentIndex = -1
|
|
|
|
anchorIndex = 0
|
|
|
|
cancelRename()
|
|
|
|
hoveredItem = null
|
|
|
|
pressedItem = null
|
|
|
|
cPress = null
|
|
|
|
}
|
|
|
|
|
2021-11-03 10:35:09 -07:00
|
|
|
function drop(target, event, pos) {
|
|
|
|
var dropPos = mapToItem(control.contentItem, pos.x, pos.y)
|
|
|
|
var dropIndex = control.indexAt(dropPos.x, dropPos.y)
|
|
|
|
var dragPos = mapToItem(control.contentItem, control.dragX, control.dragY)
|
|
|
|
var dragIndex = control.indexAt(dragPos.x, dragPos.y)
|
|
|
|
|
|
|
|
if (control.dragX === -1 || dragIndex !== dropIndex) {
|
|
|
|
dirModel.drop(control, event, dropItemAt(dropPos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function dropItemAt(pos) {
|
|
|
|
var item = control.itemAt(pos.x, pos.y)
|
|
|
|
|
|
|
|
if (item) {
|
|
|
|
if (item.blank) {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
var hOffset = Math.abs(Math.min(control.contentX, control.originX))
|
|
|
|
var hPos = mapToItem(item, pos.x + hOffset, pos.y)
|
|
|
|
|
|
|
|
if ((hPos.x < 0 || hPos.y < 0 || hPos.x > item.width || hPos.y > item.height)) {
|
|
|
|
return -1
|
|
|
|
} else {
|
|
|
|
return positioner.map(item.index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
2021-03-29 01:51:34 -07:00
|
|
|
highlightMoveDuration: 0
|
|
|
|
keyNavigationEnabled : true
|
|
|
|
keyNavigationWraps : true
|
2021-05-28 07:27:15 -07:00
|
|
|
Keys.onPressed: {
|
|
|
|
control.keyPress(event)
|
|
|
|
|
2021-03-29 01:51:34 -07:00
|
|
|
if (event.key === Qt.Key_Control) {
|
|
|
|
ctrlPressed = true
|
|
|
|
} else if (event.key === Qt.Key_Shift) {
|
|
|
|
shiftPressed = true
|
|
|
|
|
|
|
|
if (currentIndex != -1)
|
|
|
|
anchorIndex = currentIndex
|
2021-04-01 07:16:42 -07:00
|
|
|
} else if (event.key === Qt.Key_Equal && event.modifiers & Qt.ControlModifier) {
|
|
|
|
control.increaseIconSize()
|
|
|
|
} else if (event.key === Qt.Key_Minus && event.modifiers & Qt.ControlModifier) {
|
|
|
|
control.decreaseIconSize()
|
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) {
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.clearSelection()
|
2021-04-04 13:06:24 -07:00
|
|
|
event.accepted = false
|
|
|
|
}
|
|
|
|
}
|
2021-04-05 00:21:39 -07:00
|
|
|
Keys.onUpPressed: {
|
2021-04-21 10:51:17 -07:00
|
|
|
if (!editor || !editor.targetItem) {
|
|
|
|
var newIndex = positioner.nearestItem(currentIndex,
|
|
|
|
effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.UpArrow))
|
|
|
|
if (newIndex !== -1) {
|
|
|
|
currentIndex = newIndex
|
|
|
|
updateSelection(event.modifiers)
|
|
|
|
}
|
2021-04-05 00:21:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Keys.onDownPressed: {
|
2021-04-21 10:51:17 -07:00
|
|
|
if (!editor || !editor.targetItem) {
|
|
|
|
var newIndex = positioner.nearestItem(currentIndex,
|
|
|
|
effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.DownArrow))
|
|
|
|
if (newIndex !== -1) {
|
|
|
|
currentIndex = newIndex
|
|
|
|
updateSelection(event.modifiers)
|
|
|
|
}
|
2021-04-05 00:21:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Keys.onLeftPressed: {
|
2021-04-21 10:51:17 -07:00
|
|
|
if (!editor || !editor.targetItem) {
|
|
|
|
var newIndex = positioner.nearestItem(currentIndex,
|
|
|
|
effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.LeftArrow))
|
|
|
|
if (newIndex !== -1) {
|
2021-11-03 10:35:09 -07:00
|
|
|
currentIndex = newIndex
|
2021-04-21 10:51:17 -07:00
|
|
|
updateSelection(event.modifiers)
|
|
|
|
}
|
2021-04-05 00:21:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Keys.onRightPressed: {
|
2021-04-21 10:51:17 -07:00
|
|
|
if (!editor || !editor.targetItem) {
|
|
|
|
var newIndex = positioner.nearestItem(currentIndex,
|
|
|
|
effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.RightArrow))
|
|
|
|
if (newIndex !== -1) {
|
2021-11-03 10:35:09 -07:00
|
|
|
currentIndex = newIndex
|
2021-04-21 10:51:17 -07:00
|
|
|
updateSelection(event.modifiers)
|
|
|
|
}
|
2021-04-05 00:21:39 -07:00
|
|
|
}
|
|
|
|
}
|
2021-03-29 01:51:34 -07:00
|
|
|
|
|
|
|
cellHeight: {
|
2021-09-15 00:46:38 -07:00
|
|
|
var iconHeight = iconSize + (FishUI.Units.fontMetrics.height * 2) + FishUI.Units.largeSpacing * 2
|
2021-03-30 09:20:52 -07:00
|
|
|
if (isDesktopView) {
|
|
|
|
var extraHeight = calcExtraSpacing(iconHeight, control.height - topMargin - bottomMargin)
|
|
|
|
return iconHeight + extraHeight
|
|
|
|
}
|
|
|
|
return iconHeight
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
cellWidth: {
|
2021-04-09 07:49:19 -07:00
|
|
|
var iconWidth = iconSize + FishUI.Units.largeSpacing * 4
|
2021-03-30 09:20:52 -07:00
|
|
|
var extraWidth = calcExtraSpacing(iconWidth, control.width - leftMargin - rightMargin)
|
|
|
|
return iconWidth + extraWidth
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
clip: true
|
|
|
|
currentIndex: -1
|
2021-03-30 05:44:50 -07:00
|
|
|
ScrollBar.vertical: ScrollBar { }
|
2021-03-29 01:51:34 -07:00
|
|
|
|
2021-05-05 07:27:33 -07:00
|
|
|
FishUI.WheelHandler {
|
|
|
|
target: control
|
|
|
|
}
|
|
|
|
|
2021-03-29 01:51:34 -07:00
|
|
|
onPressXChanged: {
|
|
|
|
cPress = mapToItem(control.contentItem, pressX, pressY)
|
|
|
|
}
|
|
|
|
|
|
|
|
onPressYChanged: {
|
|
|
|
cPress = mapToItem(control.contentItem, pressX, pressY)
|
|
|
|
}
|
|
|
|
|
2021-04-01 01:05:15 -07:00
|
|
|
onContentXChanged: {
|
|
|
|
cancelRename()
|
|
|
|
}
|
|
|
|
|
|
|
|
onContentYChanged: {
|
|
|
|
cancelRename()
|
|
|
|
}
|
|
|
|
|
2021-03-29 01:51:34 -07:00
|
|
|
onCachedRectangleSelectionChanged: {
|
|
|
|
if (cachedRectangleSelection === null)
|
|
|
|
return
|
|
|
|
|
|
|
|
if (cachedRectangleSelection.length)
|
|
|
|
control.currentIndex[0]
|
|
|
|
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.updateSelection(cachedRectangleSelection, control.ctrlPressed)
|
|
|
|
}
|
|
|
|
|
|
|
|
Positioner {
|
|
|
|
id: positioner
|
|
|
|
enabled: true
|
|
|
|
folderModel: dirModel
|
|
|
|
perStripe: Math.floor(((control.flow == GridView.FlowLeftToRight)
|
|
|
|
? control.width : control.height) / ((control.flow == GridView.FlowLeftToRight)
|
2021-11-03 10:35:09 -07:00
|
|
|
? control.cellWidth : control.cellHeight))
|
2021-04-05 00:21:39 -07:00
|
|
|
}
|
|
|
|
|
2021-11-03 10:35:09 -07:00
|
|
|
DragDrop.DropArea {
|
2021-04-05 00:21:39 -07:00
|
|
|
anchors.fill: parent
|
|
|
|
|
2021-11-03 10:35:09 -07:00
|
|
|
onDrop: {
|
|
|
|
control.drop(control, event, mapToItem(control, event.x, event.y))
|
2021-04-05 00:21:39 -07:00
|
|
|
}
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
MouseArea {
|
|
|
|
id: _mouseArea
|
|
|
|
anchors.fill: parent
|
|
|
|
propagateComposedEvents: true
|
|
|
|
preventStealing: true
|
|
|
|
acceptedButtons: Qt.RightButton | Qt.LeftButton
|
|
|
|
hoverEnabled: true
|
|
|
|
enabled: true
|
|
|
|
z: -1
|
|
|
|
|
|
|
|
onPressed: {
|
|
|
|
control.forceActiveFocus()
|
|
|
|
|
2021-03-30 18:22:32 -07:00
|
|
|
if (control.editor && childAt(mouse.x, mouse.y) !== control.editor)
|
|
|
|
control.editor.commit()
|
|
|
|
|
2021-03-29 01:51:34 -07:00
|
|
|
pressX = mouse.x
|
|
|
|
pressY = mouse.y
|
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
// 如果找到 hoveredItem 则点击后设置成为 pressedItem
|
|
|
|
if (hoveredItem) {
|
2021-03-29 01:51:34 -07:00
|
|
|
pressedItem = hoveredItem
|
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
// 这里更改 currentIndex 会影响到范围选择
|
|
|
|
if (!control.shiftPressed)
|
|
|
|
currentIndex = pressedItem.index
|
2021-03-29 01:51:34 -07:00
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
// Shift 处理, 选择区域
|
2021-03-29 01:51:34 -07:00
|
|
|
if (control.shiftPressed && control.currentIndex !== -1) {
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.setRangeSelected(control.anchorIndex, hoveredItem.index)
|
2021-03-29 01:51:34 -07:00
|
|
|
} else {
|
2021-03-30 05:44:50 -07:00
|
|
|
// Ctrl 处理
|
2021-04-05 00:21:39 -07:00
|
|
|
if (!control.ctrlPressed && !dirModel.isSelected(hoveredItem.index)) {
|
|
|
|
dirModel.clearSelection()
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
// Item 选择
|
2021-03-29 01:51:34 -07:00
|
|
|
if (control.ctrlPressed) {
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.toggleSelected(hoveredItem.index)
|
2021-03-29 01:51:34 -07:00
|
|
|
} else {
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.setSelected(hoveredItem.index)
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
// 弹出 Item 菜单
|
|
|
|
if (mouse.buttons & Qt.RightButton) {
|
|
|
|
clearPressState()
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.openContextMenu(null, mouse.modifiers)
|
2021-03-30 05:44:50 -07:00
|
|
|
mouse.accepted = true
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// 处理空白区域点击
|
|
|
|
if (!control.ctrlPressed) {
|
|
|
|
control.currentIndex = -1
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.clearSelection()
|
2021-03-30 05:44:50 -07:00
|
|
|
}
|
2021-03-29 01:51:34 -07:00
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
// 弹出文件夹菜单
|
2021-03-29 01:51:34 -07:00
|
|
|
if (mouse.buttons & Qt.RightButton) {
|
|
|
|
clearPressState()
|
2021-04-12 19:17:23 -07:00
|
|
|
dirModel.openContextMenu(null, mouse.modifiers)
|
2021-03-29 01:51:34 -07:00
|
|
|
mouse.accepted = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onPositionChanged: {
|
|
|
|
control.ctrlPressed = (mouse.modifiers & Qt.ControlModifier)
|
|
|
|
control.shiftPressed = (mouse.modifiers & Qt.ShiftModifier)
|
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
var index = control.indexAt(mouse.x + control.contentX,
|
|
|
|
mouse.y + control.contentY)
|
|
|
|
var indexItem = control.itemAtIndex(index)
|
2021-03-29 01:51:34 -07:00
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
// Set hoveredItem.
|
|
|
|
if (indexItem) {
|
2021-03-30 09:20:52 -07:00
|
|
|
var fPos = mapToItem(indexItem.background, mouse.x, mouse.y)
|
2021-03-29 01:51:34 -07:00
|
|
|
|
2021-03-30 09:20:52 -07:00
|
|
|
if (fPos.x < 0 || fPos.y < 0
|
|
|
|
|| fPos.x > indexItem.background.width
|
|
|
|
|| fPos.y > indexItem.background.height) {
|
2021-03-29 01:51:34 -07:00
|
|
|
control.hoveredItem = null
|
|
|
|
} else {
|
2021-03-30 05:44:50 -07:00
|
|
|
control.hoveredItem = indexItem
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
2021-03-30 05:44:50 -07:00
|
|
|
} else {
|
|
|
|
control.hoveredItem = null
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update rubberband geometry.
|
|
|
|
if (control.rubberBand) {
|
2021-03-30 05:44:50 -07:00
|
|
|
var cPos = mapToItem(control.contentItem, mouse.x, mouse.y)
|
|
|
|
var leftEdge = Math.min(control.contentX, control.originX)
|
2021-03-29 01:51:34 -07:00
|
|
|
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
|
2021-03-30 05:44:50 -07:00
|
|
|
const ceil = Math.max(control.width, control.contentItem.width) + leftEdge
|
2021-03-29 01:51:34 -07:00
|
|
|
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
|
2021-03-30 05:44:50 -07:00
|
|
|
const ceil = Math.max(control.height, control.contentItem.height)
|
2021-03-29 01:51:34 -07:00
|
|
|
rB.height = Math.min(ceil - 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
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pressX != -1) {
|
2021-04-05 00:21:39 -07:00
|
|
|
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)
|
2021-04-05 00:21:39 -07:00
|
|
|
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)
|
2021-11-03 10:35:09 -07:00
|
|
|
return
|
2021-04-04 13:06:24 -07:00
|
|
|
|
2021-04-05 00:21:39 -07:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
clearPressState()
|
|
|
|
|
2024-01-23 12:43:32 -08:00
|
|
|
if (mouse.buttons & Qt.BackButton) {
|
|
|
|
control.backPress()
|
|
|
|
}
|
|
|
|
if (mouse.buttons & Qt.ForwardButton){
|
|
|
|
control.forwardPress()
|
|
|
|
}
|
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
if (mouse.buttons & Qt.RightButton) {
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.openContextMenu(null, mouse.modifiers)
|
2021-03-30 05:44:50 -07:00
|
|
|
}
|
|
|
|
}
|
2021-03-29 01:51:34 -07:00
|
|
|
|
2021-03-30 05:44:50 -07:00
|
|
|
onDoubleClicked: {
|
|
|
|
if (mouse.button === Qt.LeftButton && control.pressedItem)
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.openSelected()
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2021-09-05 14:39:56 -07:00
|
|
|
dirModel.updateSelectedItemsSize()
|
|
|
|
|
2021-04-13 10:09:01 -07:00
|
|
|
pressCanceled()
|
|
|
|
}
|
|
|
|
|
2021-03-29 01:51:34 -07:00
|
|
|
onCanceled: pressCanceled()
|
2021-03-30 23:01:22 -07:00
|
|
|
|
|
|
|
onWheel: {
|
|
|
|
if (wheel.modifiers & Qt.ControlModifier) {
|
|
|
|
if (wheel.angleDelta.y > 0)
|
|
|
|
control.increaseIconSize()
|
|
|
|
else
|
|
|
|
control.decreaseIconSize()
|
2021-03-30 23:05:03 -07:00
|
|
|
} else {
|
|
|
|
wheel.accepted = false
|
2021-03-30 23:01:22 -07:00
|
|
|
}
|
|
|
|
}
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
function clearPressState() {
|
|
|
|
pressedItem = null
|
|
|
|
pressX = -1
|
|
|
|
pressY = -1
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.unpinSelection()
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
clearPressState()
|
|
|
|
}
|
|
|
|
|
|
|
|
function rectangleSelect(x, y, width, height) {
|
|
|
|
var rows = (control.flow === GridView.FlowLeftToRight)
|
|
|
|
var axis = rows ? control.width : control.height
|
|
|
|
var step = rows ? cellWidth : cellHeight
|
|
|
|
var perStripe = Math.floor(axis / step)
|
|
|
|
var stripes = Math.ceil(control.count / perStripe)
|
2021-04-09 07:49:19 -07:00
|
|
|
var cWidth = control.cellWidth - (2 * FishUI.Units.smallSpacing)
|
|
|
|
var cHeight = control.cellHeight - (2 * FishUI.Units.smallSpacing)
|
2021-03-29 01:51:34 -07:00
|
|
|
var midWidth = control.cellWidth / 2
|
|
|
|
var midHeight = control.cellHeight / 2
|
|
|
|
var indices = []
|
|
|
|
|
|
|
|
for (var s = 0; s < stripes; s++) {
|
|
|
|
for (var i = 0; i < perStripe; i++) {
|
|
|
|
var index = (s * perStripe) + i
|
|
|
|
|
|
|
|
if (index >= control.count) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2021-04-05 00:21:39 -07:00
|
|
|
if (dirModel.isBlank(index)) {
|
2021-03-29 01:51:34 -07:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
var itemX = ((rows ? i : s) * control.cellWidth)
|
|
|
|
var itemY = ((rows ? s : i) * control.cellHeight)
|
|
|
|
|
|
|
|
if (control.effectiveLayoutDirection === Qt.RightToLeft) {
|
|
|
|
itemX -= (rows ? control.contentX : control.originX)
|
|
|
|
itemX += cWidth
|
|
|
|
itemX = (rows ? control.width : control.contentItem.width) - itemX
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the rubberband intersects this cell first to avoid doing more
|
|
|
|
// expensive work.
|
2021-04-09 07:49:19 -07:00
|
|
|
if (control.rubberBand.intersects(Qt.rect(itemX + FishUI.Units.smallSpacing, itemY + FishUI.Units.smallSpacing,
|
2021-03-29 01:51:34 -07:00
|
|
|
cWidth, cHeight))) {
|
|
|
|
var item = control.contentItem.childAt(itemX + midWidth, itemY + midHeight)
|
|
|
|
|
|
|
|
// If this is a visible item, check for intersection with the actual
|
|
|
|
// icon or label rects for better feel.
|
|
|
|
if (item && item.iconArea) {
|
|
|
|
var iconRect = Qt.rect(itemX + item.iconArea.x, itemY + item.iconArea.y,
|
|
|
|
item.iconArea.width, item.iconArea.height)
|
|
|
|
|
|
|
|
if (control.rubberBand.intersects(iconRect)) {
|
|
|
|
indices.push(index)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-04-01 01:05:15 -07:00
|
|
|
var labelRect = Qt.rect(itemX + item.labelArea.x, itemY + item.labelArea.y,
|
|
|
|
item.labelArea.width, item.labelArea.height)
|
2021-03-29 01:51:34 -07:00
|
|
|
|
|
|
|
if (control.rubberBand.intersects(labelRect)) {
|
|
|
|
indices.push(index)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Otherwise be content with the cell intersection.
|
|
|
|
indices.push(index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
control.cachedRectangleSelection = indices
|
|
|
|
}
|
|
|
|
|
|
|
|
function calcExtraSpacing(cellSize, containerSize) {
|
|
|
|
var availableColumns = Math.floor(containerSize / cellSize)
|
|
|
|
var extraSpacing = 0
|
|
|
|
if (availableColumns > 0) {
|
|
|
|
var allColumnSize = availableColumns * cellSize
|
2021-04-14 19:34:32 -07:00
|
|
|
var extraSpace = Math.max(containerSize - allColumnSize, 0)
|
2021-03-29 01:51:34 -07:00
|
|
|
extraSpacing = extraSpace / availableColumns
|
|
|
|
}
|
|
|
|
return Math.floor(extraSpacing)
|
|
|
|
}
|
2021-03-30 18:22:32 -07:00
|
|
|
|
2021-03-30 23:01:22 -07:00
|
|
|
function increaseIconSize() {
|
|
|
|
if (iconSize >= control.maximumIconSize) {
|
|
|
|
iconSize = control.maximumIconSize
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
iconSize += (iconSize * 0.1)
|
|
|
|
}
|
|
|
|
|
|
|
|
function decreaseIconSize() {
|
|
|
|
if (iconSize <= control.minimumIconSize) {
|
|
|
|
iconSize = control.minimumIconSize
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
iconSize -= (iconSize * 0.1)
|
|
|
|
}
|
|
|
|
|
2021-04-05 00:21:39 -07:00
|
|
|
function updateSelection(modifier) {
|
|
|
|
if (modifier & Qt.ShiftModifier) {
|
|
|
|
dirModel.setRangeSelected(anchorIndex, currentIndex)
|
|
|
|
} else {
|
|
|
|
dirModel.clearSelection()
|
|
|
|
dirModel.setSelected(currentIndex)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-30 18:22:32 -07:00
|
|
|
Component {
|
|
|
|
id: editorComponent
|
|
|
|
|
|
|
|
TextField {
|
|
|
|
id: _editor
|
|
|
|
visible: false
|
|
|
|
wrapMode: TextEdit.Wrap
|
|
|
|
horizontalAlignment: TextEdit.AlignHCenter
|
2021-04-09 07:49:19 -07:00
|
|
|
topPadding: FishUI.Units.smallSpacing
|
|
|
|
bottomPadding: FishUI.Units.smallSpacing
|
2021-04-21 19:24:10 -07:00
|
|
|
z: 999
|
2021-03-30 18:22:32 -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-09 07:49:19 -07:00
|
|
|
width = targetItem.width - FishUI.Units.smallSpacing
|
|
|
|
height = targetItem.labelArea.paintedHeight + FishUI.Units.largeSpacing * 2
|
2021-04-01 01:05:15 -07:00
|
|
|
x = targetItem.x + Math.abs(Math.min(control.contentX, control.originX))
|
2021-09-15 00:46:38 -07:00
|
|
|
y = pos.y - FishUI.Units.smallSpacing
|
2021-04-01 01:05:15 -07:00
|
|
|
text = targetItem.labelArea.text
|
|
|
|
targetItem.labelArea.visible = false
|
2021-04-05 00:21:39 -07:00
|
|
|
_editor.select(0, dirModel.fileExtensionBoundary(targetItem.index))
|
2021-03-30 18:22:32 -07:00
|
|
|
visible = true
|
2021-04-04 13:06:24 -07:00
|
|
|
control.interactive = false
|
2021-03-30 18:22:32 -07:00
|
|
|
} else {
|
2021-04-01 01:05:15 -07:00
|
|
|
x = 0
|
|
|
|
y = 0
|
|
|
|
width = 0
|
|
|
|
height = 0
|
2021-03-30 18:22:32 -07:00
|
|
|
visible = false
|
2021-04-04 13:06:24 -07:00
|
|
|
control.interactive = true
|
2021-03-30 18:22:32 -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-30 18:22:32 -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-30 18:22:32 -07:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onVisibleChanged: {
|
|
|
|
if (visible)
|
|
|
|
_editor.forceActiveFocus()
|
|
|
|
else
|
|
|
|
control.forceActiveFocus()
|
|
|
|
}
|
|
|
|
|
|
|
|
function commit() {
|
|
|
|
if (targetItem) {
|
2021-04-01 01:05:15 -07:00
|
|
|
targetItem.labelArea.visible = true
|
2021-04-05 00:21:39 -07:00
|
|
|
dirModel.rename(targetItem.index, text)
|
2021-03-30 18:22:32 -07:00
|
|
|
control.currentIndex = targetItem.index
|
|
|
|
targetItem = null
|
2021-04-04 13:06:24 -07:00
|
|
|
|
|
|
|
control.editor.destroy()
|
2021-03-30 18:22:32 -07:00
|
|
|
}
|
|
|
|
}
|
2021-04-01 01:05:15 -07:00
|
|
|
|
|
|
|
function cancel() {
|
|
|
|
if (targetItem) {
|
|
|
|
targetItem.labelArea.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-30 18:22:32 -07:00
|
|
|
}
|
|
|
|
}
|
2021-03-29 01:51:34 -07:00
|
|
|
}
|