Files

178 lines
6.3 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import qs.Common
import qs.DCommon.Widgets
import qs.Modals.DLauncherV2
Rectangle {
id: root
LayoutMirroring.enabled: I18n.isRtl
LayoutMirroring.childrenInherit: true
property bool imageTile: false
property real iconMargins: 0
property real iconFallbackLeftMargin: 0
property real iconFallbackRightMargin: 0
property real iconFallbackBottomMargin: 0
property real iconMaterialSizeAdjustment: Theme.spacingM
property real iconUnicodeScale: Theme.fontSizeXLarge / Theme.iconSizeLarge
property real minIconSize: Theme.iconSizeLarge
property real maxIconSize: LauncherMetrics.gridIconSize
property real iconSizeRatio: Theme.launcherImageRatio
property bool externalHighlight: false
readonly property color contentColor: isSelected ? Theme.onSelectedContainer : Theme.onSurface
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)
signal pointerMoved
readonly property string iconValue: {
if (!item)
return "";
switch (item.iconType) {
case "material":
case "nerd":
return "material:" + (item.icon || "apps");
case "unicode":
return "unicode:" + (item.icon || "");
case "composite":
return item.iconFull || "";
case "image":
default:
return item.icon || "";
}
}
readonly property int computedIconSize: Math.min(root.maxIconSize, Math.max(root.minIconSize, width * root.iconSizeRatio))
radius: Theme.cornerRadiusL
color: externalHighlight ? "transparent" : isSelected ? Theme.selectedContainer : Theme.foregroundColor(Theme.cardSurface, Theme.isFloatingWindow(root))
border.width: externalHighlight ? 0 : Theme.layerOutlineWidth
border.color: Theme.outlineMedium
opacity: (root.item?.type === "dmenu" && root.item?.data?.nonSelectable) ? 0.5 : 1.0
Rectangle {
anchors.fill: parent
radius: root.radius
color: Theme.withAlpha(root.contentColor, itemArea.pressed ? Theme.stateLayerPressed : Theme.stateLayerHover)
visible: root.isHovered || itemArea.pressed
}
DRipple {
id: rippleLayer
rippleColor: root.contentColor
cornerRadius: root.radius
}
Row {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Theme.spacingXS
spacing: Theme.spacingXS
z: 1
SourceBadge {
badgeVisible: !root.imageTile
source: root.item?.type === "app" ? (root.item.source || "") : ""
glyphSize: Theme.iconSizeSmall
}
DIcon {
name: "push_pin"
size: Theme.iconSizeSmall
color: root.contentColor
visible: root.item?.pinned === true
}
DIcon { // dmenu --multi-select checkbox
name: root.item?.data?.checked ? "check_box" : "check_box_outline_blank"
size: Theme.iconSizeSmall
color: root.item?.data?.checked ? Theme.primary : root.contentColor
visible: root.item?.type === "dmenu" && root.controller?.dmenuMultiSelect === true
}
}
Loader {
anchors.fill: parent
active: !root.imageTile
sourceComponent: Item {
Column {
anchors.centerIn: parent
spacing: Theme.spacingS
width: parent.width - Theme.spacingL * 2
AppIconRenderer {
visible: !(root.item?.type === "dmenu" && root.item?.data?.nonSelectable && !root.item?.icon)
fallbackRadius: Theme.fullRadius(width, height)
fallbackBackgroundColor: Theme.primaryContainer
fallbackTextColor: Theme.onPrimaryContainer
width: root.computedIconSize
height: root.computedIconSize
anchors.horizontalCenter: parent.horizontalCenter
iconValue: root.iconValue
iconMargins: root.iconMargins
fallbackLeftMargin: root.iconFallbackLeftMargin
fallbackRightMargin: root.iconFallbackRightMargin
fallbackBottomMargin: root.iconFallbackBottomMargin
unicodeIconScale: root.iconUnicodeScale
iconSize: root.computedIconSize
animate: root.visible && root.item?.data?.animated === true
fallbackText: root.item?.name?.charAt(0).toUpperCase() || "?"
iconColor: root.contentColor
materialIconSizeAdjustment: root.iconMaterialSizeAdjustment
}
StyledText {
width: parent.width
height: LauncherMetrics.tileLabelBlockHeight
verticalAlignment: Text.AlignTop
text: root.item?._hName ?? root.item?.name ?? ""
textFormat: root.item?._hRich ? Text.RichText : Text.PlainText
font.pixelSize: Theme.fontSizeSmall
font.weight: Theme.fontWeightMedium
font.family: Theme.fontFamily
color: root.contentColor
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
maximumLineCount: 2
wrapMode: Text.Wrap
}
}
}
}
MouseArea {
id: itemArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: mouse => {
if (mouse.button === Qt.LeftButton)
rippleLayer.trigger(mouse.x, mouse.y);
}
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: {
root.pointerMoved();
if (root.controller)
root.controller.keyboardNavigationActive = false;
}
}
}