FreeKill/Fk/RoomElement/GuanxingBox.qml
YoumuKon e121233e9d
观星美化 (#361)
拖拽卡牌悬停时可以显示金色包边
2024-07-03 09:57:06 +08:00

341 lines
9.3 KiB
QML

// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Layouts
import Fk.Pages
GraphicsBox {
id: root
property string prompt
property var cards: []
property var org_cards: []
property var movepos: []
property var dragging_card: ""
property var result: []
property var areaCapacities: []
property var areaLimits: []
property var areaNames: []
property bool free_arrange: true
property int padding: 25
title.text: luatr(prompt !== "" ? prompt : "Please arrange cards")
width: body.width + padding * 2
height: title.height + body.height + padding * 2
ColumnLayout {
id: body
x: padding
y: parent.height - padding - height
spacing: 20
Repeater {
id: areaRepeater
model: areaCapacities
Row {
spacing: 5
property int areaCapacity: modelData
property string areaName: index < areaNames.length
? qsTr(areaNames[index]) : ""
Rectangle {
anchors.verticalCenter: parent.verticalCenter
color: "#6B5D42"
width: 20
height: 100
radius: 5
Text {
anchors.fill: parent
width: 20
height: 100
text: areaName
color: "white"
font.family: fontLibian.name
font.pixelSize: 18
style: Text.Outline
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
Repeater {
id: cardRepeater
model: areaCapacity
Rectangle {
color: "#1D1E19"
width: 93
height: 130
Text {
anchors.centerIn: parent
text: areaName
color: "#59574D"
width: parent.width * 0.8
wrapMode: Text.WordWrap
}
}
}
property alias cardRepeater: cardRepeater
}
}
MetroButton {
Layout.alignment: Qt.AlignHCenter
id: buttonConfirm
text: luatr("OK")
width: 120
height: 35
onClicked: close();
}
}
Repeater {
id: cardItem
model: cards
CardItem {
x: index
y: -1
cid: modelData.cid
name: modelData.name
suit: modelData.suit
number: modelData.number
mark: modelData.mark
draggable: true
onDraggingChanged: {
if (!dragging) return;
dragging_card = this;
let i, card
for (i = 0; i < cardItem.count; i++) {
card = cardItem.itemAt(i);
if (card !== this)
card.draggable = false;
}
}
onReleased: updateCardReleased(this);
onXChanged : updateCardDragging(this);
onYChanged : updateCardDragging(this);
}
}
function updateCardDragging(_card) {
if (!_card.dragging) return;
_card.goBackAnim.stop();
_card.opacity = 0.5
let i, j
let box, pos, pile;
movepos = [];
for (j = 0; j <= result.length; j++) {
if (j >= result.length) {
arrangeCards();
return;
}
pile = areaRepeater.itemAt(j);
if (pile.y === 0) {
pile.y = j * 150
}
box = pile.cardRepeater.itemAt(0);
pos = mapFromItem(pile, box.x, box.y);
if (Math.abs(pos.y - _card.y) < 130 / 2) break;
}
if (result[j].includes(_card)) {
if (j === 0 && !free_arrange) {
arrangeCards();
return;
}
} else if (!_card.selectable) {
arrangeCards();
return;
}
let card;
let index = result[j].indexOf(_card);
if (index === -1 && result[j].length === areaCapacities[j]) {
for (i = result[j].length; i > 0; i--) {
card = result[j][i-1];
if (card === _card) continue;
if (Math.abs(card.x - _card.x) <= card.width / 2 && card.selectable) {
movepos = [j, i-1];
break;
}
}
} else {
for (i = 0; i < result[j].length; i++) {
card = result[j][i];
if (card.dragging) continue;
if (card.x > _card.x) {
movepos = [j, i - ((index !==-1 && index < i) ? 1 : 0)];
break;
}
}
if (movepos.length === 0)
movepos = [j, result[j].length - ((index === -1) ? 0 : 1)];
if (!free_arrange && j === 0 && org_cards[0].includes(_card.cid)) {
let a = 0, b = -1, c = -1;
i = 0;
while (i < result[j].length && a < org_cards[0].length) {
if (result[j][i].cid === org_cards[0][a]) {
if (b !==c) {
c = i;
break;
}
i++;
a++;
} else {
if (b === -1)
b = i;
if (org_cards[0].includes(result[j][i].cid)) {
a++;
} else {
i++;
}
}
}
if (b === -1) b = result[j].length;
if (c === -1) c = result[j].length;
if (b === c)
movepos = [j, b];
else if (movepos[1] < b || (movepos[1] > c && c !==-1))
movepos = [];
}
}
arrangeCards();
}
function updateCardReleased(_card) {
let i, j;
if (movepos.length === 2) {
for (j = 0; j < result.length; j++) {
i = result[j].indexOf(_card);
if (i !==-1) {
if (j !==movepos[0] && result[movepos[0]].length === areaCapacities[movepos[0]]) {
result[j][i] = result[movepos[0]][movepos[1]];
result[movepos[0]][movepos[1]] = _card;
if (!free_arrange && result[0].length < areaCapacities[0])
result[0].sort((a, b) => org_cards[0].indexOf(a.cid) - org_cards[0].indexOf(b.cid));
} else {
result[j].splice(i, 1);
result[movepos[0]].splice(movepos[1], 0, _card);
}
movepos = [];
break;
}
}
}
dragging_card = "";
arrangeCards();
}
function arrangeCards() {
let i, j, a, b;
let card, box, pos, pile;
let spacing;
let same_row;
let c_result = getResult();
let is_exchange = (movepos.length === 2 && !result[movepos[0]].includes(dragging_card) && result[movepos[0]].length === areaCapacities[movepos[0]])
for (j = 0; j < result.length; j++) {
pile = areaRepeater.itemAt(j);
box = pile.cardRepeater.itemAt(0);
if (pile.y === 0) {
pile.y = j * 150
}
a = result[j].length;
if (movepos.length === 2) {
if (movepos[0] === j && !result[j].includes(dragging_card) && result[j].length < areaCapacities[j]) {
a++;
} else if (movepos[0] !== j && result[j].includes(dragging_card)) {
a--;
}
}
spacing = 100;
b = 0;
for (i = 0; i < result[j].length; i++) {
card = result[j][i];
if (card.dragging) {
if (movepos.length !== 2 || movepos[0] !== j)
b++;
continue;
}
if (movepos.length === 2 && movepos[0] === j && b === movepos[1] && !is_exchange)
b++;
pos = mapFromItem(pile, box.x, box.y);
card.glow.visible = false;
if (movepos.length === 2 && result[j].length === areaCapacities[j] && movepos[0] === j && movepos[1] === b) {
card.glow.color = "gold";
card.glow.visible = true;
} else card.glow.color = "#88FFFFFF";
card.origX = (movepos.length === 2 && movepos[0] === j && b > (movepos[1] - (is_exchange ? 0 : 1))) ? (pos.x + (b - 1) * spacing + 100) : (pos.x + b * spacing);
card.origY = pos.y;
card.opacity = 1;
card.z = i + 1;
card.initialZ = i + 1;
card.maxZ = cardItem.count;
if (free_arrange || dragging_card === "")
card.selectable = true;
else if (result[j].length < areaCapacities[j] + (result[j].includes(dragging_card) ? 1 : 0))
card.selectable = (j !== 0);
else {
if (j === 0)
card.selectable = !org_cards[0].includes(dragging_card.cid) || i === org_cards[0].indexOf(dragging_card.cid);
else {
if (result[0].includes(dragging_card))
card.selectable = result[0].length < areaCapacities[0] || !org_cards[0].includes(card.cid) || card.cid === org_cards[0][result[0].indexOf(dragging_card)];
else
card.selectable = org_cards[0].includes(dragging_card.cid) || card.cid === org_cards[0][result[0].indexOf(dragging_card)];
}
}
card.draggable = (dragging_card === "") && (free_arrange || j > 0 || card.selectable);
card.goBack(true);
b++;
}
}
for (i = 0; i < areaRepeater.count; i++) {
if (result[i].length < areaLimits[i]) {
buttonConfirm.enabled = false;
break;
}
buttonConfirm.enabled = true;
}
}
function initializeCards() {
result = new Array(areaCapacities.length);
let i, j;
let k = 0;
for (i = 0; i < result.length; i++){
result[i] = [];
}
let card;
for (j = 0; j < org_cards.length; j++){
for (i = 0; i < org_cards[j].length; i++){
result[j].push(cardItem.itemAt(k));
k++;
}
}
arrangeCards();
}
function getResult() {
const ret = [];
result.forEach(t => {
const t2 = [];
t.forEach(v => t2.push(v.cid));
ret.push(t2);
});
return ret;
}
}