GridView supports up,down,left,right keys to move

This commit is contained in:
cutefishd 2021-04-05 15:21:39 +08:00
parent 10576c3529
commit cbd653013b
7 changed files with 210 additions and 73 deletions

View file

@ -28,6 +28,7 @@
#include "model/placesmodel.h"
#include "model/foldermodel.h"
#include "model/pathbarmodel.h"
#include "model/positioner.h"
#include "widgets/rubberband.h"
#include "widgets/itemviewadapter.h"
#include "desktop/desktopsettings.h"
@ -58,6 +59,7 @@ int main(int argc, char *argv[])
qmlRegisterType<PlacesModel>(uri, 1, 0, "PlacesModel");
qmlRegisterType<FolderModel>(uri, 1, 0, "FolderModel");
qmlRegisterType<PathBarModel>(uri, 1, 0, "PathBarModel");
qmlRegisterType<Positioner>(uri, 1, 0, "Positioner");
qmlRegisterType<RubberBand>(uri, 1, 0, "RubberBand");
qmlRegisterType<ItemViewAdapter>(uri, 1, 0, "ItemViewAdapter");
qmlRegisterType<DesktopSettings>(uri, 1, 0, "DesktopSettings");

View file

@ -144,6 +144,7 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const
case IconNameRole:
return item.iconName();
case ThumbnailRole: {
if (item.isLocalFile()) {
// Svg Image
if (item.mimetype() == "image/svg" ||
item.mimetype() == "image/svg+xml") {
@ -154,6 +155,7 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const
if (isSupportThumbnails(item.mimetype())) {
return "image://thumbnailer/" + item.url().toString();
}
}
return QVariant();
}

View file

@ -81,7 +81,7 @@ Item {
anchors.centerIn: parent
width: Math.min(parent.width, _image.paintedWidth)
height: Math.min(parent.height, _image.paintedHeight)
radius: Meui.Theme.smallRadius / 2
radius: height * 0.1
}
}
}

View file

@ -14,6 +14,9 @@ GridView {
property Item hoveredItem: null
property Item pressedItem: null
property alias positions: positioner.positions
property alias positioner: positioner
property int verticalDropHitscanOffset: 0
property int pressX: -1
@ -43,6 +46,50 @@ GridView {
signal keyPress(var event)
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
}
}
}
function rename() {
if (control.currentIndex != -1) {
var renameAction = control.model.action("rename")
@ -103,10 +150,42 @@ GridView {
Keys.onEscapePressed: {
if (!editor || !editor.targetItem) {
previouslySelectedItemIndex = -1
folderModel.clearSelection()
dirModel.clearSelection()
event.accepted = false
}
}
Keys.onUpPressed: {
var newIndex = positioner.nearestItem(currentIndex,
effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.UpArrow))
if (newIndex !== -1) {
currentIndex = newIndex
updateSelection(event.modifiers)
}
}
Keys.onDownPressed: {
var newIndex = positioner.nearestItem(currentIndex,
effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.DownArrow))
if (newIndex !== -1) {
currentIndex = newIndex
updateSelection(event.modifiers)
}
}
Keys.onLeftPressed: {
var newIndex = positioner.nearestItem(currentIndex,
effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.LeftArrow))
if (newIndex !== -1) {
currentIndex = newIndex;
updateSelection(event.modifiers)
}
}
Keys.onRightPressed: {
var newIndex = positioner.nearestItem(currentIndex,
effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.RightArrow))
if (newIndex !== -1) {
currentIndex = newIndex;
updateSelection(event.modifiers)
}
}
cellHeight: {
var iconHeight = iconSize + (Meui.Units.fontMetrics.height * 2) + Meui.Units.largeSpacing * 2
@ -150,7 +229,32 @@ GridView {
if (cachedRectangleSelection.length)
control.currentIndex[0]
folderModel.updateSelection(cachedRectangleSelection, control.ctrlPressed)
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)
? control.cellWidth : control.cellHeight));
}
DropArea {
id: _dropArea
anchors.fill: parent
onDropped: {
var dropPos = mapToItem(control.contentItem, drop.x, drop.y)
var dropIndex = control.indexAt(drop.x, drop.y)
var dragPos = mapToItem(control.contentItem, control.dragX, control.dragY)
var dragIndex = control.indexAt(dragPos.x, dragPos.y)
if (control.dragX == -1 || dragIndex !== dropIndex) {
}
}
}
MouseArea {
@ -182,38 +286,38 @@ GridView {
// Shift ,
if (control.shiftPressed && control.currentIndex !== -1) {
folderModel.setRangeSelected(control.anchorIndex, hoveredItem.index)
dirModel.setRangeSelected(control.anchorIndex, hoveredItem.index)
} else {
// Ctrl
if (!control.ctrlPressed && !folderModel.isSelected(hoveredItem.index)) {
folderModel.clearSelection()
if (!control.ctrlPressed && !dirModel.isSelected(hoveredItem.index)) {
dirModel.clearSelection()
}
// Item
if (control.ctrlPressed) {
folderModel.toggleSelected(hoveredItem.index)
dirModel.toggleSelected(hoveredItem.index)
} else {
folderModel.setSelected(hoveredItem.index)
dirModel.setSelected(hoveredItem.index)
}
}
// Item
if (mouse.buttons & Qt.RightButton) {
clearPressState()
folderModel.openContextMenu(null, mouse.modifiers)
dirModel.openContextMenu(null, mouse.modifiers)
mouse.accepted = true
}
} else {
//
if (!control.ctrlPressed) {
control.currentIndex = -1
folderModel.clearSelection()
dirModel.clearSelection()
}
//
if (mouse.buttons & Qt.RightButton) {
clearPressState()
folderModel.openContextMenu(null, mouse.modifiers)
dirModel.openContextMenu(null, mouse.modifiers)
mouse.accepted = true
}
}
@ -277,11 +381,11 @@ GridView {
}
if (pressX != -1) {
if (pressedItem != null && folderModel.isSelected(pressedItem.index)) {
if (pressedItem != null && dirModel.isSelected(pressedItem.index)) {
control.dragX = mouse.x
control.dragY = mouse.y
control.verticalDropHitscanOffset = pressedItem.y + (pressedItem.height / 2)
folderModel.dragSelected(mouse.x, mouse.y)
dirModel.dragSelected(mouse.x, mouse.y)
control.dragX = -1
control.dragY = -1
clearPressState()
@ -289,7 +393,7 @@ GridView {
if (control.editor && control.editor.targetItem)
return;
folderModel.pinSelection()
dirModel.pinSelection()
control.rubberBand = rubberBandObject.createObject(control.contentItem, {x: cPress.x, y: cPress.y})
control.interactive = false
}
@ -300,13 +404,13 @@ GridView {
clearPressState()
if (mouse.buttons & Qt.RightButton) {
folderModel.openContextMenu(null, mouse.modifiers)
dirModel.openContextMenu(null, mouse.modifiers)
}
}
onDoubleClicked: {
if (mouse.button === Qt.LeftButton && control.pressedItem)
folderModel.openSelected()
dirModel.openSelected()
}
onReleased: pressCanceled()
@ -337,7 +441,7 @@ GridView {
control.interactive = true
control.cachedRectangleSelection = null
folderModel.unpinSelection()
dirModel.unpinSelection()
}
clearPressState()
@ -363,7 +467,7 @@ GridView {
break
}
if (folderModel.isBlank(index)) {
if (dirModel.isBlank(index)) {
continue
}
@ -440,6 +544,18 @@ GridView {
iconSize -= (iconSize * 0.1)
}
function updateSelection(modifier) {
if (modifier & Qt.ShiftModifier) {
dirModel.setRangeSelected(anchorIndex, currentIndex)
} else {
dirModel.clearSelection()
dirModel.setSelected(currentIndex)
if (currentIndex == -1)
previouslySelectedItemIndex = -1
previouslySelectedItemIndex = currentIndex
}
}
Component {
id: editorComponent
@ -463,7 +579,7 @@ GridView {
y = pos.y - Meui.Units.largeSpacing
text = targetItem.labelArea.text
targetItem.labelArea.visible = false
_editor.select(0, folderModel.fileExtensionBoundary(targetItem.index))
_editor.select(0, dirModel.fileExtensionBoundary(targetItem.index))
visible = true
control.interactive = false
} else {
@ -500,7 +616,7 @@ GridView {
function commit() {
if (targetItem) {
targetItem.labelArea.visible = true
folderModel.rename(targetItem.index, text)
dirModel.rename(targetItem.index, text)
control.currentIndex = targetItem.index
targetItem = null

View file

@ -1,6 +1,7 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.0
import MeuiKit 1.0 as Meui
Item {
@ -78,6 +79,21 @@ Item {
fillMode: Image.PreserveAspectFit
asynchronous: true
smooth: false
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Item {
width: _image.width
height: _image.height
Rectangle {
anchors.centerIn: parent
width: Math.min(parent.width, _image.paintedWidth)
height: Math.min(parent.height, _image.paintedHeight)
radius: height * 0.1
}
}
}
}
}

View file

@ -96,7 +96,7 @@ ListView {
Keys.onEscapePressed: {
if (!editor || !editor.targetItem) {
previouslySelectedItemIndex = -1
folderModel.clearSelection()
dirModel.clearSelection()
event.accepted = false
}
}
@ -134,7 +134,7 @@ ListView {
if (cachedRectangleSelection.length)
control.currentIndex[0]
folderModel.updateSelection(cachedRectangleSelection, control.ctrlPressed)
dirModel.updateSelection(cachedRectangleSelection, control.ctrlPressed)
}
onContentXChanged: {
@ -165,7 +165,7 @@ ListView {
onDoubleClicked: {
if (mouse.button === Qt.LeftButton && control.pressedItem)
folderModel.openSelected()
dirModel.openSelected()
}
onPressed: {
@ -192,36 +192,36 @@ ListView {
if (!control.ctrlPressed) {
control.currentIndex = -1
control.previouslySelectedItemIndex = -1
folderModel.clearSelection()
dirModel.clearSelection()
}
if (mouse.buttons & Qt.RightButton) {
clearPressState()
folderModel.openContextMenu(null, mouse.modifiers)
dirModel.openContextMenu(null, mouse.modifiers)
mouse.accepted = true
}
} else {
pressedItem = hoveredItem
if (control.shiftPressed && control.currentIndex !== -1) {
folderModel.setRangeSelected(control.anchorIndex, hoveredItem.index)
dirModel.setRangeSelected(control.anchorIndex, hoveredItem.index)
} else {
if (!control.ctrlPressed && !folderModel.isSelected(hoveredItem.index)) {
if (!control.ctrlPressed && !dirModel.isSelected(hoveredItem.index)) {
previouslySelectedItemIndex = -1
folderModel.clearSelection()
dirModel.clearSelection()
}
if (control.ctrlPressed)
folderModel.toggleSelected(hoveredItem.index)
dirModel.toggleSelected(hoveredItem.index)
else
folderModel.setSelected(hoveredItem.index)
dirModel.setSelected(hoveredItem.index)
}
control.currentIndex = hoveredItem.index
if (mouse.buttons & Qt.RightButton) {
clearPressState()
folderModel.openContextMenu(null, mouse.modifiers)
dirModel.openContextMenu(null, mouse.modifiers)
mouse.accepted = true
}
}
@ -289,11 +289,11 @@ ListView {
// Drag
if (pressX != -1) {
if (pressedItem != null && folderModel.isSelected(pressedItem.index)) {
if (pressedItem != null && dirModel.isSelected(pressedItem.index)) {
control.dragX = mouse.x
control.dragY = mouse.y
control.verticalDropHitscanOffset = pressedItem.y + (pressedItem.height / 2)
folderModel.dragSelected(mouse.x, mouse.y)
dirModel.dragSelected(mouse.x, mouse.y)
control.dragX = -1
control.dragY = -1
clearPressState()
@ -301,7 +301,7 @@ ListView {
if (control.editor && control.editor.targetItem)
return;
folderModel.pinSelection()
dirModel.pinSelection()
control.rubberBand = rubberBandObject.createObject(control.contentItem, {x: cPress.x, y: cPress.y})
control.interactive = false
}
@ -329,7 +329,7 @@ ListView {
control.interactive = true
control.cachedRectangleSelection = null
folderModel.unpinSelection()
dirModel.unpinSelection()
}
clearPressState()
@ -354,10 +354,10 @@ ListView {
function updateSelection(modifier) {
if (modifier & Qt.ShiftModifier) {
folderModel.setRangeSelected(anchorIndex, currentIndex)
dirModel.setRangeSelected(anchorIndex, currentIndex)
} else {
folderModel.clearSelection()
folderModel.setSelected(currentIndex)
dirModel.clearSelection()
dirModel.setSelected(currentIndex)
if (currentIndex == -1)
previouslySelectedItemIndex = -1
previouslySelectedItemIndex = currentIndex
@ -386,7 +386,7 @@ ListView {
text = targetItem.labelArea.text
targetItem.labelArea.visible = false
targetItem.labelArea2.visible = false
_editor.select(0, folderModel.fileExtensionBoundary(targetItem.index))
_editor.select(0, dirModel.fileExtensionBoundary(targetItem.index))
visible = true
control.interactive = false
} else {
@ -422,7 +422,7 @@ ListView {
if (targetItem) {
targetItem.labelArea.visible = true
targetItem.labelArea2.visible = true
folderModel.rename(targetItem.index, text)
dirModel.rename(targetItem.index, text)
control.currentIndex = targetItem.index
targetItem = null

View file

@ -10,7 +10,7 @@ import "./Dialogs"
Item {
id: folderPage
property alias currentUrl: folderModel.url
property alias currentUrl: dirModel.url
property Item currentView: _viewLoader.item
property int statusBarHeight: 30
@ -39,21 +39,22 @@ Item {
}
FolderModel {
id: folderModel
id: dirModel
viewAdapter: viewAdapter
Component.onCompleted: {
if (arg)
folderModel.url = arg
dirModel.url = arg
else
folderModel.url = folderModel.homePath()
dirModel.url = dirModel.homePath()
}
}
ItemViewAdapter {
id: viewAdapter
adapterView: _viewLoader.item
adapterModel: folderModel
adapterModel: _viewLoader.item.positioner ? _viewLoader.item.positioner : dirModel
adapterIconSize: 40
adapterVisibleArea: Qt.rect(_viewLoader.item.contentX, _viewLoader.item.contentY,
_viewLoader.item.contentWidth, _viewLoader.item.contentHeight)
@ -90,7 +91,7 @@ Item {
}
Component.onCompleted: {
folderModel.requestRename.connect(rename)
dirModel.requestRename.connect(rename)
}
Component {
@ -109,14 +110,14 @@ Item {
Label {
Layout.alignment: Qt.AlignLeft
text: folderModel.count == 1 ? qsTr("%1 item").arg(folderModel.count)
: qsTr("%1 items").arg(folderModel.count)
text: dirModel.count == 1 ? qsTr("%1 item").arg(dirModel.count)
: qsTr("%1 items").arg(dirModel.count)
}
Label {
Layout.alignment: Qt.AlignLeft
text: qsTr("%1 selected").arg(folderModel.selectionCound)
visible: folderModel.selectionCound >= 1
text: qsTr("%1 selected").arg(dirModel.selectionCound)
visible: dirModel.selectionCound >= 1
}
Item {
@ -127,8 +128,8 @@ Item {
Layout.fillHeight: true
Layout.alignment: Qt.AlignRight
text: qsTr("Empty Trash")
onClicked: folderModel.emptyTrash()
visible: folderModel.url === "trash:/"
onClicked: dirModel.emptyTrash()
visible: dirModel.url === "trash:/"
}
}
}
@ -139,7 +140,7 @@ Item {
FolderGridView {
id: _gridView
model: folderModel
model: dirModel
delegate: FolderGridItem {}
leftMargin: Meui.Units.largeSpacing
@ -163,7 +164,7 @@ Item {
FolderListView {
id: _folderListView
model: folderModel
model: dirModel
topMargin: Meui.Units.largeSpacing
leftMargin: Meui.Units.largeSpacing
@ -219,36 +220,36 @@ Item {
function onKeyPress(event) {
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return)
folderModel.openSelected()
dirModel.openSelected()
else if (event.key === Qt.Key_C && event.modifiers & Qt.ControlModifier)
folderModel.copy()
dirModel.copy()
else if (event.key === Qt.Key_X && event.modifiers & Qt.ControlModifier)
folderModel.cut()
dirModel.cut()
else if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier)
folderModel.paste()
dirModel.paste()
else if (event.key === Qt.Key_F2)
folderModel.requestRename()
dirModel.requestRename()
else if (event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier)
folderPage.requestPathEditor()
else if (event.key === Qt.Key_A && event.modifiers & Qt.ControlModifier)
folderModel.selectAll()
dirModel.selectAll()
else if (event.key === Qt.Key_Backspace)
folderModel.up()
dirModel.up()
else if (event.key === Qt.Key_Delete)
folderModel.keyDeletePress()
dirModel.keyDeletePress()
}
}
function openUrl(url) {
folderModel.url = url
dirModel.url = url
_viewLoader.item.forceActiveFocus()
}
function goBack() {
folderModel.goBack()
dirModel.goBack()
}
function goForward() {
folderModel.goForward()
dirModel.goForward()
}
}