424 lines
12 KiB
QML
424 lines
12 KiB
QML
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import QtQuick
|
|
import QtQuick.Layouts
|
|
import Fk
|
|
import Fk.Pages
|
|
import Fk.RoomElement
|
|
|
|
GraphicsBox {
|
|
id: root
|
|
property string prompt
|
|
property var cards: []
|
|
property var org_cards: []
|
|
property var result: []
|
|
property var areaCapacities: []
|
|
property var areaLimits: []
|
|
property var areaNames: []
|
|
property var dragging_card: ""
|
|
property var movepos: []
|
|
property bool free_arrange: true
|
|
property bool cancelable: false
|
|
property string poxi_type: ""
|
|
property string pattern: "."
|
|
property int size: 0
|
|
property int padding: 25
|
|
|
|
title.text: Backend.translate(prompt !== "" ? Util.processPrompt(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: 10
|
|
|
|
Repeater {
|
|
id: areaRepeater
|
|
model: areaCapacities
|
|
|
|
Row {
|
|
spacing: 7
|
|
|
|
property int areaCapacity: modelData
|
|
property string areaName: index < areaNames.length ? qsTr(Backend.translate(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: (size === 0) ? areaCapacity : 1
|
|
|
|
Rectangle {
|
|
color: "#1D1E19"
|
|
width: (size === 0) ? 93 : size * 100 - 7
|
|
height: 130
|
|
|
|
}
|
|
}
|
|
property alias cardRepeater: cardRepeater
|
|
}
|
|
}
|
|
|
|
Row {
|
|
anchors.bottom: parent.bottom
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
spacing: 32
|
|
|
|
MetroButton {
|
|
width: 120
|
|
height: 35
|
|
id: buttonConfirm
|
|
text: luatr("OK")
|
|
onClicked: {
|
|
close();
|
|
roomScene.state = "notactive";
|
|
const reply = JSON.stringify(getResult());
|
|
ClientInstance.replyToServer("", reply);
|
|
}
|
|
}
|
|
|
|
MetroButton {
|
|
width: 120
|
|
height: 35
|
|
text: luatr("Cancel")
|
|
visible: root.cancelable
|
|
onClicked: {
|
|
close();
|
|
roomScene.state = "notactive";
|
|
const ret = [];
|
|
let i;
|
|
for (i = 0; i < result.length; i++) {
|
|
ret.push([]);
|
|
}
|
|
const reply = JSON.stringify(ret);
|
|
ClientInstance.replyToServer("", reply);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Repeater {
|
|
id: cardItem
|
|
model: cards
|
|
|
|
CardItem {
|
|
x: index
|
|
y: -1
|
|
cid: modelData.cid
|
|
name: modelData.name
|
|
suit: modelData.suit
|
|
number: modelData.number
|
|
draggable: true
|
|
onReleased: updateCardReleased(this);
|
|
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;
|
|
}
|
|
}
|
|
onXChanged : updateCardDragging(this);
|
|
onYChanged : updateCardDragging(this);
|
|
onSelectedChanged : updateCardSelected(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 * 140
|
|
}
|
|
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 updateCardSelected(_card) {
|
|
let i = result[0].indexOf(_card);
|
|
let j;
|
|
if (i === -1) {
|
|
if (result[0].length < areaCapacities[0]) {
|
|
if (free_arrange || !org_cards[0].includes(_card.cid)) {
|
|
for (j = 1; j < result.length; j++) {
|
|
i = result[j].indexOf(_card);
|
|
if (i !==-1) {
|
|
result[j].splice(i, 1);
|
|
result[0].push(_card);
|
|
arrangeCards();
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
i = 0;
|
|
j = 0;
|
|
while (i < result[0].length && j < org_cards[0].length) {
|
|
if (org_cards[0][j] === _card.cid) break;
|
|
if (result[0][i].cid === org_cards[0][j]) {
|
|
i++;
|
|
j++;
|
|
} else {
|
|
if (org_cards[0].includes(result[0][i].cid))
|
|
j++;
|
|
else
|
|
i++;
|
|
}
|
|
}
|
|
let index;
|
|
for (j = 1; j < result.length; j++) {
|
|
index = result[j].indexOf(_card);
|
|
if (index !== -1) {
|
|
result[j].splice(index, 1);
|
|
result[0].splice(i, 0, _card);
|
|
arrangeCards();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (j = 1; j < result.length; j++) {
|
|
if (result[j].length < areaCapacities[j]) {
|
|
result[0].splice(i, 1);
|
|
result[j].push(_card);
|
|
arrangeCards();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 * 140
|
|
}
|
|
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 = (size > 0 && a > size) ? ((size - 1) * 100 / (a - 1)) : 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;
|
|
card.chosenInBox = (movepos.length === 2 && result[j].length === areaCapacities[j] && movepos[0] === j && movepos[1] === b);
|
|
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 (poxi_type !== "")
|
|
card.selectable = lcall("PoxiFilter", poxi_type, card.cid, [dragging_card.cid], c_result, org_cards);
|
|
else if (pattern !== ".")
|
|
card.selectable = lcall("CardFitPattern", card.cid, pattern);
|
|
else {
|
|
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 = poxi_type ? lcall("PoxiFeasible", poxi_type, [], c_result, org_cards) : 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;
|
|
}
|
|
}
|