Files

212 lines
7.1 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import qs.Common
import qs.Modules.Dock
Item {
id: delegateItem
required property var strip
function activate() {
if (isOverflowToggle)
strip.overflowExpanded = !strip.overflowExpanded;
else
dockButton?.activate();
}
readonly property var hoveredButton: dockButton?.showTooltip ? dockButton : null
readonly property bool interactionActive: isDragging
required property var modelData
required property int index
activeFocusOnTab: (!isInOverflow || strip.overflowExpanded) && itemData.type !== "separator"
Accessible.name: dockButton?.tooltipText ?? I18n.tr("Applications")
Accessible.role: Accessible.Button
onActiveFocusChanged: if (activeFocus)
strip.surfaceContext.ensureVisible(delegateItem)
Keys.onPressed: event => {
if (event.key === Qt.Key_Space) {
dockButton?.activate();
event.accepted = true;
return;
}
if (!strip.renderItems)
return;
const previous = strip.isVertical ? Qt.Key_Up : (I18n.isRtl ? Qt.Key_Right : Qt.Key_Left);
const next = strip.isVertical ? Qt.Key_Down : (I18n.isRtl ? Qt.Key_Left : Qt.Key_Right);
const direction = event.key === previous ? -1 : event.key === next ? 1 : 0;
if (!direction)
return;
for (let i = index + direction; i >= 0 && i < strip.renderedCount; i += direction) {
const target = strip.itemAt(i);
if (!target?.activeFocusOnTab)
continue;
target.forceActiveFocus();
event.accepted = true;
return;
}
}
Keys.onEnterPressed: activate()
Keys.onReturnPressed: {
if (isOverflowToggle)
strip.overflowExpanded = !strip.overflowExpanded;
else
dockButton?.activate();
}
property var dockButton: {
switch (itemData.type) {
case "launcher":
return launcherButton;
case "trash":
return trashButton;
case "overflow-toggle":
return overflowButton;
default:
return button;
}
}
property var itemData: modelData
readonly property bool isOverflowToggle: itemData.type === "overflow-toggle"
readonly property bool isTrash: itemData.type === "trash"
readonly property bool isInOverflow: itemData.isInOverflow === true
readonly property bool isDragging: button.dragging
clip: false
z: isDragging ? 100 : 0
visible: !isInOverflow || strip.overflowExpanded
opacity: (isInOverflow && !strip.overflowExpanded) ? 0 : 1
scale: (isInOverflow && !strip.overflowExpanded) ? 0.8 : 1
readonly property bool collapsed: isInOverflow && !strip.overflowExpanded
readonly property real primarySize: {
if (itemData.type === "separator")
return 8;
if (strip.options.compact === false && !strip.isVertical)
return strip.targetSize + Theme.listItemHeight * 2;
return strip.targetSize;
}
width: collapsed ? 0 : (strip.isVertical ? strip.crossSize : primarySize)
height: collapsed ? 0 : (strip.isVertical ? primarySize : strip.crossSize)
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
property real shiftOffset: {
if (!strip.renderItems || strip.draggedIndex < 0 || !itemData.isPinned || itemData.type === "separator")
return 0;
if (delegateItem.index === strip.draggedIndex)
return 0;
const dragIdx = strip.draggedIndex;
const dropIdx = strip.dropTargetIndex;
const myIdx = delegateItem.index;
const shiftAmount = strip.targetSize + strip.itemSpacing;
if (dropIdx < 0)
return 0;
if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx)
return -shiftAmount;
if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx)
return shiftAmount;
return 0;
}
readonly property var shiftSpringParams: Theme.springPreset("fast", 150)
SpringMotion {
id: shiftSpring
enabled: !strip.suppressShiftAnimation
positionEpsilon: 0.05
velocityEpsilon: 0.05
stiffness: delegateItem.shiftSpringParams.stiffness
damping: delegateItem.shiftSpringParams.damping
Component.onCompleted: snapTo(delegateItem.shiftOffset)
}
onShiftOffsetChanged: shiftSpring.retarget(shiftOffset)
transform: Translate {
x: strip.isVertical ? 0 : shiftSpring.value
y: strip.isVertical ? shiftSpring.value : 0
}
Rectangle {
visible: itemData.type === "separator"
width: strip.isVertical ? strip.iconSize * 0.5 : 2
height: strip.isVertical ? 2 : strip.iconSize * 0.5
color: Theme.outlineHeavy
radius: 1
anchors.centerIn: parent
}
DockOverflowButton {
id: overflowButton
options: strip.options
visible: isOverflowToggle
anchors.centerIn: parent
width: delegateItem.width
height: delegateItem.height
actualIconSize: strip.iconSize * (strip.options.iconSizePercentage ?? 100) / 100
overflowCount: itemData.overflowCount || 0
overflowExpanded: strip.overflowExpanded
isVertical: strip.isVertical
onClicked: strip.overflowExpanded = !strip.overflowExpanded
}
DockLauncherButton {
id: launcherButton
options: strip.options
visible: itemData.type === "launcher"
anchors.centerIn: parent
width: delegateItem.width
height: delegateItem.height
actualIconSize: strip.iconSize * (strip.options.iconSizePercentage ?? 100) / 100
dockApps: strip
}
DockTrashButton {
id: trashButton
options: strip.options
visible: itemData.type === "trash"
anchors.centerIn: parent
width: delegateItem.width
height: delegateItem.height
actualIconSize: strip.iconSize * (strip.options.iconSizePercentage ?? 100) / 100
dockApps: strip
contextMenu: strip.trashContextMenu
parentDockScreen: strip.dockScreen
}
DockAppButton {
id: button
options: strip.options
visible: !isOverflowToggle && itemData.type !== "separator" && itemData.type !== "launcher" && itemData.type !== "trash"
anchors.centerIn: parent
width: delegateItem.width
height: delegateItem.height
actualIconSize: strip.iconSize * (strip.options.iconSizePercentage ?? 100) / 100
appData: itemData
contextMenu: strip.contextMenu
dockApps: strip
index: delegateItem.index
parentDockScreen: strip.dockScreen
showWindowTitle: itemData?.type === "window" || itemData?.type === "grouped"
windowTitle: {
const title = itemData?.toplevel?.title || "(Unnamed)";
return title.length > 50 ? title.substring(0, 47) + "..." : title;
}
}
}