GUI: hand zone - fixed wrong dragging effect while click on card, improved dragging animation, fixed wrong click if user return card to the original place

This commit is contained in:
Oleg Agafonov 2023-11-30 09:21:43 +04:00
parent cd07bbfdf2
commit e534497834
6 changed files with 39 additions and 34 deletions

View file

@ -20,7 +20,7 @@
import java.util.*;
/**
* Panel for stack and hand zones, component for lookAt and reveal windows (CardInfoWindowDialog)
* GUI: panel for stack and hand zones, component for lookAt and reveal windows (CardInfoWindowDialog)
*
* @author BetaSteward_at_googlemail.com, JayDi85
*/

View file

@ -6,10 +6,7 @@ import org.apache.log4j.Logger;
import java.awt.Component;
import java.util.EnumMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
import javax.swing.JButton;
public class MageUI {
@ -38,7 +35,7 @@ public class MageUI {
// catch errors in popup threads (example: card popup over cards or chat/log messages)
t = ThreadUtils.findRealException(r, t);
if (t != null) {
if (t != null && !(t instanceof CancellationException)) {
logger.error("Catch unhandled error in POPUP thread: " + t.getMessage(), t);
}
}

View file

@ -36,10 +36,7 @@ import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
/**
* Class that handles the callbacks from the card panels to mage to display big
@ -68,11 +65,11 @@ public class MageActionCallback implements ActionCallback {
// higher value -> the effect will appear earlier (depends on the card size)
public static final int HAND_CARDS_COMPARE_GAP_X = 30;
public static final int HAND_CARDS_MIN_DISTANCE_TO_START_DRAGGING = 20; // do not drag on small distance (click instead)
public static final int GO_DOWN_ON_DRAG_Y_OFFSET = 0;
public static final int GO_UP_ON_DRAG_Y_OFFSET = 0;
public static final int MIN_X_OFFSET_REQUIRED = 20;
private Popup tooltipPopup;
private BigCard bigCard;
@ -275,24 +272,29 @@ public class MageActionCallback implements ActionCallback {
clearDragging(cardPanel);
this.startedDragging = false;
if (maxXOffset < MIN_X_OFFSET_REQUIRED) { // we need this for protection from small card movements
// default click simulation // TODO: replace to normal clicked events (change dialogs)
cardPanel.requestFocusInWindow();
DefaultActionCallback.instance.mouseClicked(data.getGameId(), data.getCard());
// Closes popup & enlarged view if a card/Permanent is selected
hideTooltipPopup();
if (isDragging && maxXOffset < HAND_CARDS_MIN_DISTANCE_TO_START_DRAGGING) {
// if user returned card to original place
// outdated code, HAND_CARDS_MIN_DISTANCE_TO_START_DRAGGING already used for wrong drag protection,
// so no needs in additional clicks here
//logger.info("User drag card to original place");
//simulateCardClick(data);
}
e.consume();
} else {
// default click simulation
cardPanel.requestFocusInWindow();
DefaultActionCallback.instance.mouseClicked(data.getGameId(), data.getCard());
// Closes popup & enlarged view if a card/Permanent is selected
hideTooltipPopup();
simulateCardClick(data);
e.consume();
}
}
private void simulateCardClick(TransferData data) {
MageCard cardPanel = data.getComponent().getTopPanelRef();
cardPanel.requestFocusInWindow();
DefaultActionCallback.instance.mouseClicked(data.getGameId(), data.getCard());
// closes popup & enlarged view if a card/permanent is selected
hideTooltipPopup();
}
private void clearDragging(MageCard clearCard) {
if (this.startedDragging && prevCardPanel != null && clearCard != null) {
// distribute cards between cards container and a drag container
@ -314,7 +316,6 @@ public class MageActionCallback implements ActionCallback {
@Override
public void mouseMoved(MouseEvent e, TransferData data) {
// MouseEvent can be null for custom hints calls, e.g. from choose dialog
if (!Plugins.instance.isCardPluginLoaded()) {
return;
}
@ -341,14 +342,22 @@ public class MageActionCallback implements ActionCallback {
// only allow draging with the left mouse button
return;
}
Point mouse = new Point(e.getX(), e.getY());
SwingUtilities.convertPointToScreen(mouse, data.getComponent());
if (!isDragging
&& Math.abs(mouse.x - initialMousePos.x) < HAND_CARDS_MIN_DISTANCE_TO_START_DRAGGING
&& Math.abs(mouse.y - initialMousePos.y) < HAND_CARDS_MIN_DISTANCE_TO_START_DRAGGING) {
// users do clicks while mouse moving, so it's not a drag and must be ignored
return;
}
isDragging = true;
prevCardPanel = cardPanel;
Point cardPanelLocationOld = cardPanel.getCardLocation().getCardPoint();
Point mouse = new Point(e.getX(), e.getY());
SwingUtilities.convertPointToScreen(mouse, data.getComponent());
int xOffset = 0; // starting position
int newX = Math.max(initialCardPos.x + (int) (mouse.getX() - initialMousePos.x) - xOffset, 0); // TODO: fix
int newX = Math.max(initialCardPos.x + (int) (mouse.getX() - initialMousePos.x) - xOffset, 0);
cardPanel.setCardBounds(
newX,
cardPanelLocationOld.y,
@ -432,7 +441,8 @@ public class MageActionCallback implements ActionCallback {
private void sortAndAnimateDraggingHandCards(List<MageCard> cards, MageCard source, boolean includeSource) {
// special offset, allows to switch with first card
source.setCardLocation(source.getCardLocation().getCardX() - HAND_CARDS_COMPARE_GAP_X, source.getCardLocation().getCardY());
int draggingOffsetX = 0; // if you need side effect while moving then use HAND_CARDS_COMPARE_GAP_X (but it looks bad)
source.setCardLocation(source.getCardLocation().getCardX() - draggingOffsetX, source.getCardLocation().getCardY());
// sorting card components, so the effect above will be applied too
cards.sort(Comparator.comparingInt(cp -> cp.getCardLocation().getCardX()));

View file

@ -7,10 +7,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
@ -45,7 +42,7 @@ public class LinePool {
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
t = ThreadUtils.findRealException(r, t);
if (t != null) {
if (t != null && !(t instanceof CancellationException)) {
// TODO: show sound errors in client logs?
//logger.error("Catch unhandled error in SOUND thread: " + t.getMessage(), t);
}

View file

@ -317,6 +317,7 @@ public class GameController implements GameCallback {
}
user.get().addGame(playerId, gameSession);
logger.debug("Player " + player.getName() + ' ' + playerId + " has " + joinType + " gameId: " + game.getId());
// TODO: force user update?!
managerFactory.chatManager().broadcast(chatId, "", game.getPlayer(playerId).getLogName() + " has " + joinType + " the game", MessageColor.ORANGE, true, game, MessageType.GAME, null);
checkStart();
}

View file

@ -65,7 +65,7 @@ public class ThreadExecutorImpl implements ThreadExecutor {
// catch errors in CALL threads (from client commands)
t = ThreadUtils.findRealException(r, t);
if (t != null) {
if (t != null && !(t instanceof CancellationException)) {
logger.error("Catch unhandled error in CALL thread: " + t.getMessage(), t);
}
}
@ -84,7 +84,7 @@ public class ThreadExecutorImpl implements ThreadExecutor {
// catch errors in GAME threads (from game processing)
t = ThreadUtils.findRealException(r, t);
if (t != null) {
if (t != null && !(t instanceof CancellationException)) {
// it's impossible to brake game thread in normal use case, so each bad use case must be researched
logger.error("Catch unhandled error in GAME thread: " + t.getMessage(), t);
}