pragma ComponentBehavior: Bound import QtQuick import qs.Common import qs.Widgets Rectangle { id: root property var item: null property bool isSelected: false property bool isHovered: itemArea.containsMouse property var controller: null property int flatIndex: -1 signal clicked signal rightClicked(real mouseX, real mouseY) radius: Theme.cornerRadius color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryPressed : "transparent" border.width: isSelected ? 2 : 0 border.color: Theme.primary readonly property string imageSource: { if (!item?.data) return ""; var data = item.data; if (data.imageUrl) return data.imageUrl; if (data.imagePath) return data.imagePath; if (data.path && isImageFile(data.path)) return data.path; return ""; } readonly property bool useImage: imageSource.length > 0 readonly property bool useIconProvider: !useImage && item?.iconType === "image" function isImageFile(path) { if (!path) return false; var ext = path.split('.').pop().toLowerCase(); return ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp"].indexOf(ext) >= 0; } Item { anchors.fill: parent anchors.margins: 4 Rectangle { id: imageContainer anchors.fill: parent radius: Theme.cornerRadius - 2 color: Theme.surfaceContainerHigh clip: true CachingImage { anchors.fill: parent visible: root.useImage imagePath: root.imageSource maxCacheSize: 256 } Image { id: iconImage anchors.fill: parent visible: root.useIconProvider source: root.useIconProvider ? "image://icon/" + (root.item?.icon || "application-x-executable") : "" sourceSize.width: parent.width * 2 sourceSize.height: parent.height * 2 fillMode: Image.PreserveAspectCrop cache: false asynchronous: true } DankIcon { anchors.centerIn: parent visible: !root.useImage && !root.useIconProvider && root.item?.iconType !== "unicode" name: root.item?.icon ?? "image" size: Math.min(parent.width, parent.height) * 0.4 color: Theme.surfaceVariantText } StyledText { anchors.centerIn: parent visible: root.item?.iconType === "unicode" text: root.item?.icon ?? "" font.pixelSize: Math.min(parent.width, parent.height) * 0.4 color: Theme.surfaceVariantText } Rectangle { anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom height: labelText.implicitHeight + Theme.spacingS * 2 color: Theme.withAlpha(Theme.surfaceContainer, 0.85) visible: root.item?.name?.length > 0 StyledText { id: labelText anchors.fill: parent anchors.margins: Theme.spacingXS text: root.item?.name ?? "" font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceText elide: Text.ElideRight horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Rectangle { anchors.top: parent.top anchors.right: parent.right anchors.margins: Theme.spacingXS width: 20 height: 20 radius: 10 color: Theme.primary visible: root.isSelected DankIcon { anchors.centerIn: parent name: "check" size: 14 color: Theme.primaryText } } } } MouseArea { id: itemArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: mouse => { if (mouse.button === Qt.RightButton) { var scenePos = mapToItem(null, mouse.x, mouse.y); root.rightClicked(scenePos.x, scenePos.y); return; } root.clicked(); } onPositionChanged: { if (root.controller) root.controller.keyboardNavigationActive = false; } } }