* Warning, you must call trimGrid() after all cards inserted
*
* @param newCard Card to add to the cardGrid array.
*/
private void sortIntoGrid(CardView newCard, CardView duplicatedFromCard) {
// fast put duplicated card to the same place as original
if (duplicatedFromCard != null) {
for (List> gridRow : cardGrid) {
for (List
> targetRow;
if (separateCreatures) {
// separate mode (two rows mode)
// row 1 for creatures
// row 2 for other
// row 2 must exists
if (cardGrid.size() < 2) {
cardGrid.add(1, new ArrayList<>());
maxStackSize.add(1, 0);
// Populate with stacks matching the first row
for (int i = 0; i < cardGrid.get(0).size(); ++i) {
cardGrid.get(1).add(new ArrayList<>());
}
}
// workaround to fix wrong sorting on one card insert (if no creatures then trim will remove first row)
boolean isFirstRowWithCreatures = true;
for (int i = 0; i < cardGrid.get(0).size(); ++i) {
if (cardGrid.get(0).get(i).stream().anyMatch(card -> !card.isCreature())) {
isFirstRowWithCreatures = false;
break;
}
}
if (!isFirstRowWithCreatures) {
// move all cards to row 2 (at first position)
for (int i = 0; i < cardGrid.get(0).size(); ++i) {
if (!cardGrid.get(0).get(i).isEmpty()) {
cardGrid.get(1).add(cardGrid.get(0).get(i));
}
}
cardGrid.get(0).clear();
while (cardGrid.get(0).size() < cardGrid.get(1).size()) {
cardGrid.get(0).add(new ArrayList<>());
}
}
if (newCard.isCreature()) {
// creature cards goes to row 1
targetRow = cardGrid.get(0);
} else {
// non-creature cards goes to row 2
targetRow = cardGrid.get(1);
}
} else {
// one row mode
targetRow = cardGrid.get(0);
}
// Find the right column to insert into
boolean didInsert = false;
for (int currentColumn = 0; currentColumn < targetRow.size(); ++currentColumn) {
// Find an item from this column
CardView cardInColumn = null;
for (List
> gridRow : cardGrid) {
for (CardView card : gridRow.get(currentColumn)) {
cardInColumn = card;
break;
}
}
// No card in this column?
if (cardInColumn == null) {
// Error, should not have an empty column
logger.error("Empty column! " + currentColumn);
} else {
CardViewComparator cardComparator = cardSort.getComparator();
int res = cardComparator.compare(newCard, cardInColumn);
if (res <= 0) {
// Insert into this col, but if less, then we need to create a new col here first
if (res < 0) {
for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) {
cardGrid.get(rowIndex).add(currentColumn, new ArrayList<>());
}
}
targetRow.get(currentColumn).add(newCard);
didInsert = true;
break;
} else {
// Nothing to do, go to next iteration
}
}
}
// If nothing else, insert in a new column after everything else
if (!didInsert) {
for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) {
cardGrid.get(rowIndex).add(new ArrayList<>());
}
targetRow.get(targetRow.size() - 1).add(newCard);
}
// empty row trim (trimGrid) must be called from outside after all cards inserted
}
/**
* Delete any empty columns / rows from the grid, and eleminate any empty
* space in stacks
*/
private void trimGrid() {
// Compact stacks and rows
for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) {
List
> gridRow = cardGrid.get(rowIndex);
int rowMaxStackSize = 0;
for (List
> aCardGrid : cardGrid) {
if (!aCardGrid.get(colIndex).isEmpty()) {
hasContent = true;
break;
}
}
if (!hasContent) {
for (List
> aCardGrid : cardGrid) {
aCardGrid.remove(colIndex);
}
--colIndex;
}
}
}
// Clean up extra column header count labels
while (stackCountLabels.size() > cardGrid.size()) {
List
> gridRow = cardGrid.get(rowIndex);
for (int colIndex = 0; colIndex < gridRow.size(); ++colIndex) {
List
Click on the count label to select/unselect cards stack." : "")
);
countLabel.setVerticalAlignment(smallMode ? JLabel.CENTER : JLabel.TOP);
if (DebugUtil.GUI_DECK_EDITOR_DRAW_COUNT_LABEL_BORDER) {
countLabel.setBorder(BorderFactory.createLineBorder(Color.green));
}
}
private List> gridRow = cardGrid.get(rowIndex);
for (int colIndex = 0; colIndex < gridRow.size(); ++colIndex) {
if (stackCountLabels.size() < rowIndex
|| stackCountLabels.get(rowIndex).size() < colIndex
|| !countLabel.equals(stackCountLabels.get(rowIndex).get(colIndex))) {
continue;
}
return gridRow.get(colIndex);
}
}
return new ArrayList<>();
}
private static void makeButtonPopup(final AbstractButton button, final JPopupMenu popup) {
button.addActionListener(e -> popup.show(button, 0, button.getHeight()));
}
}
/**
* Note: This class can't just be a JPanel, because a JPanel doesn't draw when
* it has Opaque = false, but this class needs to go into a JLayeredPane while
* being translucent, so it NEEDS Opaque = false in order to behave correctly.
* Thus this simple class is needed to implement a translucent box in a
* JLayeredPane.
*/
class SelectionBox extends JComponent {
public SelectionBox() {
setOpaque(false);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g = g.create();
g.setColor(new Color(100, 100, 200, 128));
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(new Color(0, 0, 255));
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g.dispose();
}
}