noctalia
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: cardDeck
|
||||
|
||||
required property int animationDuration
|
||||
property real animationIndex: 0
|
||||
required property int cardRadius
|
||||
required property int cardSpacing
|
||||
required property int cardStripWidth
|
||||
required property int cardsShown
|
||||
property real centerWidth: parent.width * centerWidthRatio
|
||||
required property real centerWidthRatio
|
||||
property real centerX: width / 2 - centerWidth / 2
|
||||
property int currentIndex: 0
|
||||
required property int filteredCount
|
||||
required property var filteredModel
|
||||
property int halfVisible: Math.floor(visibleCount / 2)
|
||||
property real runningIndex: 0
|
||||
required property real shearFactor
|
||||
property int sideCount: Math.floor(cardsShown / 2) - 1
|
||||
property int visibleCount: cardsShown
|
||||
|
||||
signal applyRequested(int index)
|
||||
|
||||
function navigateTo(idx) {
|
||||
var maxLead = Math.max(1, halfVisible - 1);
|
||||
if (Math.abs(runningIndex - animationIndex) >= maxLead)
|
||||
return;
|
||||
|
||||
var newIdx = wrappedIndex(idx);
|
||||
var diff = 0;
|
||||
|
||||
if (filteredCount > 0) {
|
||||
diff = newIdx - currentIndex;
|
||||
var half = filteredCount / 2;
|
||||
if (diff > half)
|
||||
diff -= filteredCount;
|
||||
else if (diff < -half)
|
||||
diff += filteredCount;
|
||||
}
|
||||
|
||||
runningIndex += diff;
|
||||
animationIndex = runningIndex;
|
||||
currentIndex = newIdx;
|
||||
}
|
||||
function randomJump() {
|
||||
var rnd = Math.floor(Math.random() * filteredCount);
|
||||
if (rnd === currentIndex)
|
||||
rnd = (rnd + 1) % filteredCount;
|
||||
navigateTo(rnd);
|
||||
}
|
||||
function slotToWidth(slot) {
|
||||
var t = Math.min(Math.abs(slot), 1);
|
||||
return centerWidth + (cardStripWidth - centerWidth) * t;
|
||||
}
|
||||
function slotToX(slot) {
|
||||
var rightEdge = centerX + centerWidth + cardSpacing;
|
||||
var leftEdge = centerX - cardSpacing - cardStripWidth;
|
||||
|
||||
if (slot >= 0 && slot <= 1)
|
||||
return centerX + (rightEdge - centerX) * slot;
|
||||
if (slot > 1)
|
||||
return rightEdge + (slot - 1) * (cardStripWidth + cardSpacing);
|
||||
if (slot >= -1 && slot < 0)
|
||||
return centerX + (leftEdge - centerX) * (-slot);
|
||||
if (slot < -1)
|
||||
return leftEdge + (slot + 1) * (cardStripWidth + cardSpacing);
|
||||
return 0;
|
||||
}
|
||||
function wrappedIndex(idx) {
|
||||
return ((idx % filteredCount) + filteredCount) % filteredCount;
|
||||
}
|
||||
|
||||
function jumpTo(idx) {
|
||||
animBehavior.enabled = false;
|
||||
runningIndex = idx;
|
||||
animationIndex = idx;
|
||||
currentIndex = idx;
|
||||
reenableTimer.restart();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: reenableTimer
|
||||
|
||||
interval: 0
|
||||
|
||||
onTriggered: animBehavior.enabled = true
|
||||
}
|
||||
|
||||
width: (cardsShown - 3) * cardStripWidth + (cardsShown - 3) * cardSpacing + centerWidth
|
||||
|
||||
Behavior on animationIndex {
|
||||
id: animBehavior
|
||||
|
||||
NumberAnimation {
|
||||
duration: cardDeck.animationDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
transform: Matrix4x4 {
|
||||
property real s: cardDeck.shearFactor
|
||||
|
||||
matrix: Qt.matrix4x4(1, s, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: cardDeck.filteredCount > 0 ? cardDeck.visibleCount : 0
|
||||
|
||||
delegate: Rectangle {
|
||||
id: card
|
||||
|
||||
property real fractionalSlot: offset + (cardDeck.runningIndex - cardDeck.animationIndex)
|
||||
property bool isCenter: offset === 0
|
||||
property int modelIndex: cardDeck.wrappedIndex(Math.round(cardDeck.runningIndex) + offset)
|
||||
property int offset: index - cardDeck.halfVisible
|
||||
|
||||
signal applyRequested
|
||||
|
||||
border.color: isCenter ? Color.mOutline : Color.mSurface
|
||||
border.width: isCenter ? Style.borderM : Style.borderS
|
||||
color: "transparent"
|
||||
height: cardDeck.height
|
||||
opacity: Math.max(0, Math.min(1, cardDeck.halfVisible - Math.abs(fractionalSlot)))
|
||||
radius: cardDeck.cardRadius
|
||||
visible: (x + width) > 0 && x < cardDeck.width
|
||||
width: cardDeck.slotToWidth(fractionalSlot)
|
||||
x: cardDeck.slotToX(fractionalSlot)
|
||||
y: 0
|
||||
z: isCenter ? 100 : cardDeck.visibleCount - Math.abs(offset)
|
||||
|
||||
Card {
|
||||
animationDuration: cardDeck.animationDuration
|
||||
centerWidth: cardDeck.centerWidth
|
||||
filePath: cardDeck.filteredModel[card.modelIndex]?.filePath ?? ""
|
||||
isCenter: card.isCenter
|
||||
isVideo: cardDeck.filteredModel[card.modelIndex]?.isVideo ?? false
|
||||
radius: cardDeck.cardRadius
|
||||
thumbnailPath: cardDeck.filteredModel[card.modelIndex]?.thumbnail ?? ""
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: card.isCenter ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
|
||||
onClicked: {
|
||||
if (card.isCenter)
|
||||
cardDeck.applyRequested(card.modelIndex);
|
||||
}
|
||||
|
||||
//
|
||||
onWheel: function (wheel) {
|
||||
if (wheel.angleDelta.y > 0)
|
||||
cardDeck.navigateTo(cardDeck.currentIndex - 1);
|
||||
else if (wheel.angleDelta.y < 0)
|
||||
cardDeck.navigateTo(cardDeck.currentIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user