GUI: added gui scale support for skip and phase button on game panel (part of #969, #6887):

- reworked skip and phase buttons to use layouts instead IDE designer;
- added GUI scale support skip and phase buttons (depend on dialogs font size from preferences settings);
This commit is contained in:
Oleg Agafonov 2024-07-28 18:01:15 +04:00
parent 8186b35dfb
commit 1d701df0e8
8 changed files with 274 additions and 144 deletions

View file

@ -78,7 +78,7 @@ public class HoverButton extends JPanel implements MouseListener {
private boolean doGainFade = true; private boolean doGainFade = true;
public HoverButton(String text, Image image, Rectangle size) { public HoverButton(String text, Image image, Rectangle size) {
this(text, image, image, null, image, size); this(text, image, image, image, image, size);
if (image == null) { if (image == null) {
throw new IllegalArgumentException("Image can't be null"); throw new IllegalArgumentException("Image can't be null");
} }
@ -370,10 +370,6 @@ public class HoverButton extends JPanel implements MouseListener {
this.drawSet = true; this.drawSet = true;
} }
public void update(String text, Image image) {
update(text, image, this.hoverImage, this.selectedImage, this.disabledImage, this.imageSize);
}
public void update(String text, Image image, Image hover, Image selected, Image disabled, Rectangle size) { public void update(String text, Image image, Image hover, Image selected, Image disabled, Rectangle size) {
this.text = text; this.text = text;
this.image = image; this.image = image;
@ -381,7 +377,7 @@ public class HoverButton extends JPanel implements MouseListener {
this.selectedImage = selected; this.selectedImage = selected;
this.disabledImage = disabled; this.disabledImage = disabled;
this.imageSize = size; this.imageSize = size;
repaint(); this.invalidate();
} }
public void execute() { public void execute() {

View file

@ -1,6 +1,7 @@
package mage.client.components; package mage.client.components;
import mage.client.dialog.PreferencesDialog; import mage.client.dialog.PreferencesDialog;
import mage.client.util.GUISizeHelper;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
@ -12,19 +13,25 @@ import java.awt.*;
*/ */
public class KeyboundButton extends JButton { public class KeyboundButton extends JButton {
private float guiScale = 1.0f;
private final String key; private final String key;
private boolean showKey; private boolean showKey;
private String drawingText; private String drawingText;
private static final Font keyFont = new Font(Font.SANS_SERIF, Font.BOLD, 13); private Font keyFont;
private boolean tinting = false; private boolean tinting = false;
public KeyboundButton(String key, boolean showKey) { public KeyboundButton(String key, boolean showKey) {
this.key = key; this.key = key;
this.showKey = showKey; this.showKey = showKey;
updateFont();
updateDrawingText(); updateDrawingText();
} }
private void updateFont() {
this.keyFont = new Font(Font.SANS_SERIF, Font.BOLD, sizeMod(13));
}
private void updateDrawingText() { private void updateDrawingText() {
if (this.showKey) { if (this.showKey) {
this.drawingText = PreferencesDialog.getCachedKeyText(key); this.drawingText = PreferencesDialog.getCachedKeyText(key);
@ -33,6 +40,12 @@ public class KeyboundButton extends JButton {
} }
} }
public void updateGuiScale(float guiScale) {
this.guiScale = guiScale;
updateFont();
invalidate();
}
public void setShowKey(boolean showKey) { public void setShowKey(boolean showKey) {
this.showKey = showKey; this.showKey = showKey;
updateDrawingText(); updateDrawingText();
@ -48,7 +61,7 @@ public class KeyboundButton extends JButton {
if (tinting) { if (tinting) {
sg.setColor(new Color(0, 0, 0, 32)); sg.setColor(new Color(0, 0, 0, 32));
sg.fillRoundRect(2, 2, getWidth() - 4, getHeight() - 4, 6, 6); sg.fillRoundRect(sizeMod(2), sizeMod(2), getWidth() - sizeMod(4), getHeight() - sizeMod(4), sizeMod(6), sizeMod(6));
} }
sg.setColor(tinting ? Color.lightGray : Color.white); sg.setColor(tinting ? Color.lightGray : Color.white);
@ -58,7 +71,7 @@ public class KeyboundButton extends JButton {
int textWidth = sg.getFontMetrics(keyFont).stringWidth(this.drawingText); int textWidth = sg.getFontMetrics(keyFont).stringWidth(this.drawingText);
int centerX = (getWidth() - textWidth) / 2; int centerX = (getWidth() - textWidth) / 2;
sg.drawString(this.drawingText, centerX, 28); sg.drawString(this.drawingText, centerX, sizeMod(28));
} }
} finally { } finally {
sg.dispose(); sg.dispose();
@ -70,4 +83,12 @@ public class KeyboundButton extends JButton {
this.tinting = tinting; this.tinting = tinting;
repaint(); repaint();
} }
private int sizeMod(int value) {
return GUISizeHelper.guiSizeScale(value, this.guiScale);
}
private float sizeMod(float value) {
return GUISizeHelper.guiSizeScale(value, this.guiScale);
}
} }

View file

@ -29,6 +29,7 @@ import mage.constants.*;
import mage.game.events.PlayerQueryEvent; import mage.game.events.PlayerQueryEvent;
import mage.players.PlayableObjectStats; import mage.players.PlayableObjectStats;
import mage.players.PlayableObjectsList; import mage.players.PlayableObjectsList;
import mage.util.DebugUtil;
import mage.util.MultiAmountMessage; import mage.util.MultiAmountMessage;
import mage.view.*; import mage.view.*;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -64,7 +65,12 @@ public final class GamePanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(GamePanel.class); private static final Logger logger = Logger.getLogger(GamePanel.class);
private static final String YOUR_HAND = "Your hand"; private static final String YOUR_HAND = "Your hand";
private static final int X_PHASE_WIDTH = 55;
private static final int SKIP_BUTTONS_SPACE_H = 3;
private static final int SKIP_BUTTONS_SPACE_V = 3;
private static final int PHASE_BUTTONS_SPACE_H = 3;
private static final int PHASE_BUTTONS_SPACE_V = 3;
private static final String CMD_AUTO_ORDER_FIRST = "cmdAutoOrderFirst"; private static final String CMD_AUTO_ORDER_FIRST = "cmdAutoOrderFirst";
private static final String CMD_AUTO_ORDER_LAST = "cmdAutoOrderLast"; private static final String CMD_AUTO_ORDER_LAST = "cmdAutoOrderLast";
@ -188,6 +194,27 @@ public final class GamePanel extends javax.swing.JPanel {
initComponents = true; initComponents = true;
initComponents(); initComponents();
// prepare commands buttons panel with flow layout (instead custom from IDE)
// size changes in helper method at the end
// TODO: remove IDE form file (it useless anyway due many custom code in init)
if (DebugUtil.GUI_GAME_DRAW_COMMAND_BUTTONS_PANEL_BORDER) {
pnlShortCuts.setBorder(BorderFactory.createLineBorder(Color.red));
}
pnlShortCuts.removeAll();
pnlShortCuts.setLayout(null); // real layout on size settings
pnlShortCuts.add(btnSkipToNextTurn);
pnlShortCuts.add(btnSkipToEndTurn);
pnlShortCuts.add(btnSkipToNextMain);
pnlShortCuts.add(btnSkipToYourTurn);
pnlShortCuts.add(btnSkipStack);
pnlShortCuts.add(btnSkipToEndStepBeforeYourTurn);
pnlShortCuts.add(txtHoldPriority);
//pnlShortCuts.add(btnToggleMacro);
pnlShortCuts.add(btnSwitchHands);
pnlShortCuts.add(btnCancelSkip);
pnlShortCuts.add(btnConcede);
pnlShortCuts.add(btnStopWatching);
pickNumber = new PickNumberDialog(); pickNumber = new PickNumberDialog();
MageFrame.getDesktop().add(pickNumber, JLayeredPane.MODAL_LAYER); MageFrame.getDesktop().add(pickNumber, JLayeredPane.MODAL_LAYER);
@ -426,7 +453,7 @@ public final class GamePanel extends javax.swing.JPanel {
// hand + stack panels // hand + stack panels
// the stack takes up a portion of the possible space (GUISizeHelper.stackWidth) // the stack takes up a portion of the possible space (GUISizeHelper.stackWidth)
// TODO: research and delete rare used settings
int newStackWidth = pnlHelperHandButtonsStackArea.getWidth() * GUISizeHelper.stackWidth / 100; int newStackWidth = pnlHelperHandButtonsStackArea.getWidth() * GUISizeHelper.stackWidth / 100;
newStackWidth = Math.max(410, newStackWidth); newStackWidth = Math.max(410, newStackWidth);
Dimension newDimension = new Dimension( Dimension newDimension = new Dimension(
@ -451,11 +478,48 @@ public final class GamePanel extends javax.swing.JPanel {
userChatPanel.changeGUISize(GUISizeHelper.chatFont); userChatPanel.changeGUISize(GUISizeHelper.chatFont);
gameChatPanel.changeGUISize(GUISizeHelper.chatFont); gameChatPanel.changeGUISize(GUISizeHelper.chatFont);
// skip buttons // skip buttons - sizes
newDimension = new Dimension(newStackWidth, (int) pnlShortCuts.getPreferredSize().getHeight()); // must be able to put controls in 2 rows
float guiScale = GUISizeHelper.dialogGuiScale;
int hGap = GUISizeHelper.guiSizeScale(SKIP_BUTTONS_SPACE_H, guiScale);
int vGap = GUISizeHelper.guiSizeScale(SKIP_BUTTONS_SPACE_V, guiScale);
newDimension = new Dimension(newStackWidth, (4 * vGap) + (2 * GUISizeHelper.gameCommandButtonHeight));
pnlShortCuts.setLayout(new FlowLayout(FlowLayout.RIGHT, hGap, vGap));
pnlShortCuts.setPreferredSize(newDimension); pnlShortCuts.setPreferredSize(newDimension);
pnlShortCuts.setMinimumSize(newDimension); pnlShortCuts.setMinimumSize(newDimension);
pnlShortCuts.setMaximumSize(newDimension); pnlShortCuts.setMaximumSize(newDimension);
// skip buttons - sizes
Dimension strictSize = new Dimension(2 * GUISizeHelper.gameCommandButtonHeight, GUISizeHelper.gameCommandButtonHeight);
setSkipButtonSize(btnCancelSkip, guiScale, strictSize);
setSkipButtonSize(btnSkipToNextTurn, guiScale, strictSize);
setSkipButtonSize(btnSkipToEndTurn, guiScale, strictSize);
setSkipButtonSize(btnSkipToEndStepBeforeYourTurn, guiScale, strictSize);
setSkipButtonSize(btnSkipToYourTurn, guiScale, strictSize);
setSkipButtonSize(btnSkipToNextMain, guiScale, strictSize);
setSkipButtonSize(btnSkipStack, guiScale, strictSize);
setSkipButtonSize(btnConcede, guiScale, strictSize);
setSkipButtonSize(btnToggleMacro, guiScale, strictSize);
setSkipButtonSize(btnSwitchHands, guiScale, strictSize);
setSkipButtonSize(btnStopWatching, guiScale, strictSize);
pnlShortCuts.invalidate();
// phase buttons - sizes
int buttonSize = GUISizeHelper.gamePhaseButtonSize;
guiScale = GUISizeHelper.dialogGuiScale;
hGap = GUISizeHelper.guiSizeScale(PHASE_BUTTONS_SPACE_H, guiScale);
vGap = GUISizeHelper.guiSizeScale(PHASE_BUTTONS_SPACE_V, guiScale);
BoxLayout layout = new BoxLayout(jPhases, BoxLayout.Y_AXIS);
jPhases.setLayout(layout);
int fullPhaseWidth = Math.round(1.5f * GUISizeHelper.gamePhaseButtonSize);
jPhases.setPreferredSize(new Dimension(fullPhaseWidth, (vGap * phaseButtons.size()) + (buttonSize * phaseButtons.size())));
jPhases.setMaximumSize(new Dimension(fullPhaseWidth, Short.MAX_VALUE));
phaseButtons.forEach((phaseName, phaseButton) -> {
phaseButton.setPreferredSize(new Dimension(buttonSize, buttonSize));
});
// phase buttons - active size
if (lastGameData.game != null) {
updateActivePhase(lastGameData.game.getStep());
}
if (themeReload) { if (themeReload) {
reloadThemeRelatedGraphic(); reloadThemeRelatedGraphic();
@ -463,18 +527,19 @@ public final class GamePanel extends javax.swing.JPanel {
} }
private void reloadThemeRelatedGraphic() { private void reloadThemeRelatedGraphic() {
// skip buttons // skip buttons - images
btnCancelSkip.setIcon(new ImageIcon(ImageManagerImpl.instance.getCancelSkipButtonImage())); int buttonHeight = GUISizeHelper.gameCommandButtonHeight;
btnSkipToNextTurn.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipNextTurnButtonImage())); setSkipButtonImage(btnCancelSkip, ImageManagerImpl.instance.getCancelSkipButtonImage(buttonHeight));
btnSkipToEndTurn.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipEndTurnButtonImage())); setSkipButtonImage(btnSkipToNextTurn, ImageManagerImpl.instance.getSkipNextTurnButtonImage(buttonHeight));
btnSkipToEndStepBeforeYourTurn.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipEndStepBeforeYourTurnButtonImage())); setSkipButtonImage(btnSkipToEndTurn, ImageManagerImpl.instance.getSkipEndTurnButtonImage(buttonHeight));
btnSkipToYourTurn.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipYourNextTurnButtonImage())); setSkipButtonImage(btnSkipToEndStepBeforeYourTurn, ImageManagerImpl.instance.getSkipEndStepBeforeYourTurnButtonImage(buttonHeight));
btnSkipToNextMain.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipMainButtonImage())); setSkipButtonImage(btnSkipToYourTurn, ImageManagerImpl.instance.getSkipYourNextTurnButtonImage(buttonHeight));
btnSkipStack.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipStackButtonImage())); setSkipButtonImage(btnSkipToNextMain, ImageManagerImpl.instance.getSkipMainButtonImage(buttonHeight));
btnConcede.setIcon(new ImageIcon(ImageManagerImpl.instance.getConcedeButtonImage())); setSkipButtonImage(btnSkipStack, ImageManagerImpl.instance.getSkipStackButtonImage(buttonHeight));
btnToggleMacro.setIcon(new ImageIcon(ImageManagerImpl.instance.getToggleRecordMacroButtonImage())); setSkipButtonImage(btnConcede, ImageManagerImpl.instance.getConcedeButtonImage(buttonHeight));
btnSwitchHands.setIcon(new ImageIcon(ImageManagerImpl.instance.getSwitchHandsButtonImage())); setSkipButtonImage(btnToggleMacro, ImageManagerImpl.instance.getToggleRecordMacroButtonImage(buttonHeight));
btnStopWatching.setIcon(new ImageIcon(ImageManagerImpl.instance.getStopWatchButtonImage())); setSkipButtonImage(btnSwitchHands, ImageManagerImpl.instance.getSwitchHandsButtonImage(buttonHeight));
setSkipButtonImage(btnStopWatching, ImageManagerImpl.instance.getStopWatchButtonImage(buttonHeight));
// hotkeys for skip buttons // hotkeys for skip buttons
boolean displayButtonText = PreferencesDialog.getCurrentTheme().isShortcutsVisibleForSkipButtons(); boolean displayButtonText = PreferencesDialog.getCurrentTheme().isShortcutsVisibleForSkipButtons();
@ -489,7 +554,9 @@ public final class GamePanel extends javax.swing.JPanel {
// phase buttons // phase buttons
phaseButtons.forEach((phaseName, phaseButton) -> { phaseButtons.forEach((phaseName, phaseButton) -> {
phaseButton.update(phaseButton.getText(), ImageManagerImpl.instance.getPhaseImage(phaseName)); Image buttonImage = ImageManagerImpl.instance.getPhaseImage(phaseName, GUISizeHelper.gamePhaseButtonSize);
Rectangle buttonRect = new Rectangle(buttonImage.getWidth(null), buttonImage.getHeight(null));
phaseButton.update(phaseButton.getText(), buttonImage, buttonImage, buttonImage, buttonImage, buttonRect);
}); });
// player panels // player panels
@ -513,6 +580,22 @@ public final class GamePanel extends javax.swing.JPanel {
} }
} }
private void setSkipButtonImage(JButton button, Image image) {
button.setIcon(new ImageIcon(image));
}
private void setSkipButtonSize(JComponent button, float guiScale, Dimension size) {
if (button instanceof KeyboundButton) {
((KeyboundButton) button).updateGuiScale(guiScale);
}
// no needs in size - it controlled by button's icon
if (true) return;
button.setMinimumSize(size);
button.setPreferredSize(size);
button.setMaximumSize(size);
}
private void saveDividerLocations() { private void saveDividerLocations() {
// save panel sizes and divider locations. // save panel sizes and divider locations.
Rectangle rec = MageFrame.getDesktop().getBounds(); Rectangle rec = MageFrame.getDesktop().getBounds();
@ -564,7 +647,6 @@ public final class GamePanel extends javax.swing.JPanel {
bigCard.setMinimumSize(bbDimension); bigCard.setMinimumSize(bbDimension);
bigCard.setPreferredSize(bbDimension); bigCard.setPreferredSize(bbDimension);
pnlShortCuts.revalidate(); pnlShortCuts.revalidate();
pnlShortCuts.repaint();
for (PlayAreaPanel p : players.values()) { for (PlayAreaPanel p : players.values()) {
p.getPlayerPanel().sizePlayerPanel(smallMode); p.getPlayerPanel().sizePlayerPanel(smallMode);
} }
@ -576,7 +658,6 @@ public final class GamePanel extends javax.swing.JPanel {
bigCard.setMinimumSize(bbDimension); bigCard.setMinimumSize(bbDimension);
bigCard.setPreferredSize(bbDimension); bigCard.setPreferredSize(bbDimension);
pnlShortCuts.revalidate(); pnlShortCuts.revalidate();
pnlShortCuts.repaint();
for (PlayAreaPanel p : players.values()) { for (PlayAreaPanel p : players.values()) {
p.getPlayerPanel().sizePlayerPanel(smallMode); p.getPlayerPanel().sizePlayerPanel(smallMode);
} }
@ -893,7 +974,7 @@ public final class GamePanel extends javax.swing.JPanel {
} }
if (lastGameData.game.getStep() != null) { if (lastGameData.game.getStep() != null) {
updatePhases(lastGameData.game.getStep()); updateActivePhase(lastGameData.game.getStep());
this.txtStep.setText(lastGameData.game.getStep().toString()); this.txtStep.setText(lastGameData.game.getStep().toString());
} else { } else {
logger.debug("Step is empty"); logger.debug("Step is empty");
@ -1261,63 +1342,63 @@ public final class GamePanel extends javax.swing.JPanel {
this.stackObjects.loadCards(game.getStack(), bigCard, gameId, true); this.stackObjects.loadCards(game.getStack(), bigCard, gameId, true);
} }
/** private void updateActivePhase(PhaseStep currentStep) {
* Update phase buttons\labels. if (currentStep == null) {
*/
private void updatePhases(PhaseStep step) {
if (step == null) {
logger.warn("step is null");
return; return;
} }
if (currentStep != null) {
currentStep.setLocation(prevPoint); switch (currentStep) {
}
switch (step) {
case UNTAP: case UNTAP:
updateButton("Untap"); updatePhaseButtons("Untap");
break; break;
case UPKEEP: case UPKEEP:
updateButton("Upkeep"); updatePhaseButtons("Upkeep");
break; break;
case DRAW: case DRAW:
updateButton("Draw"); updatePhaseButtons("Draw");
break; break;
case PRECOMBAT_MAIN: case PRECOMBAT_MAIN:
updateButton("Main1"); updatePhaseButtons("Main1");
break; break;
case BEGIN_COMBAT: case BEGIN_COMBAT:
updateButton("Combat_Start"); updatePhaseButtons("Combat_Start");
break; break;
case DECLARE_ATTACKERS: case DECLARE_ATTACKERS:
updateButton("Combat_Attack"); updatePhaseButtons("Combat_Attack");
break; break;
case DECLARE_BLOCKERS: case DECLARE_BLOCKERS:
updateButton("Combat_Block"); updatePhaseButtons("Combat_Block");
break; break;
case FIRST_COMBAT_DAMAGE: case FIRST_COMBAT_DAMAGE:
case COMBAT_DAMAGE: case COMBAT_DAMAGE:
updateButton("Combat_Damage"); updatePhaseButtons("Combat_Damage");
break; break;
case END_COMBAT: case END_COMBAT:
updateButton("Combat_End"); updatePhaseButtons("Combat_End");
break; break;
case POSTCOMBAT_MAIN: case POSTCOMBAT_MAIN:
updateButton("Main2"); updatePhaseButtons("Main2");
break; break;
case END_TURN: case END_TURN:
updateButton("Cleanup"); case CLEANUP:
updatePhaseButtons("Cleanup");
break; break;
default: default:
break; break;
} }
} }
private void updateButton(String name) { private void updatePhaseButtons(String currentPhaseName) {
if (phaseButtons.containsKey(name)) { phaseButtons.forEach((phaseName, phaseButton) -> {
currentStep = phaseButtons.get(name); if (phaseName.equals(currentPhaseName)) {
prevPoint = currentStep.getLocation(); //phaseButton.setBorder(this.phaseButtonBorderActive);
currentStep.setLocation(prevPoint.x - 15, prevPoint.y); phaseButton.setAlignmentX(Component.CENTER_ALIGNMENT);
} else {
//phaseButton.setBorder(this.phaseButtonBorderInactive);
phaseButton.setAlignmentX(Component.LEFT_ALIGNMENT);
} }
});
jPhases.invalidate();
} }
// Called if the game frame is deactivated because the tabled the deck editor or other frames go to foreground // Called if the game frame is deactivated because the tabled the deck editor or other frames go to foreground
@ -2530,8 +2611,7 @@ public final class GamePanel extends javax.swing.JPanel {
jPhases = new JPanel(); jPhases = new JPanel();
jPhases.setBackground(new Color(0, 0, 0, 0)); jPhases.setBackground(new Color(0, 0, 0, 0));
jPhases.setLayout(null); // layout on gui size
jPhases.setPreferredSize(new Dimension(X_PHASE_WIDTH, 435));
MouseAdapter phasesMouseAdapter = new MouseAdapter() { MouseAdapter phasesMouseAdapter = new MouseAdapter() {
@Override @Override
@ -2539,6 +2619,11 @@ public final class GamePanel extends javax.swing.JPanel {
mouseClickPhaseBar(evt); mouseClickPhaseBar(evt);
} }
}; };
/// phase buttons
if (DebugUtil.GUI_GAME_DRAW_PHASE_BUTTONS_PANEL_BORDER) {
jPhases.setBorder(BorderFactory.createLineBorder(Color.red));
}
String[] phases = {"Untap", "Upkeep", "Draw", "Main1", String[] phases = {"Untap", "Upkeep", "Draw", "Main1",
"Combat_Start", "Combat_Attack", "Combat_Block", "Combat_Damage", "Combat_End", "Combat_Start", "Combat_Attack", "Combat_Block", "Combat_Damage", "Combat_End",
"Main2", "Cleanup", "Next_Turn"}; "Main2", "Cleanup", "Next_Turn"};
@ -2546,15 +2631,6 @@ public final class GamePanel extends javax.swing.JPanel {
createPhaseButton(name, phasesMouseAdapter); createPhaseButton(name, phasesMouseAdapter);
} }
int i = 0;
for (String name : phaseButtons.keySet()) {
HoverButton hoverButton = phaseButtons.get(name);
hoverButton.setAlignmentX(LEFT_ALIGNMENT);
hoverButton.setBounds(X_PHASE_WIDTH - 36, i * 36, 36, 36);
jPhases.add(hoverButton);
i++;
}
pnlReplay.setOpaque(false); pnlReplay.setOpaque(false);
helper = new HelperPanel(); helper = new HelperPanel();
@ -2938,12 +3014,14 @@ public final class GamePanel extends javax.swing.JPanel {
} }
private void createPhaseButton(String name, MouseAdapter mouseAdapter) { private void createPhaseButton(String name, MouseAdapter mouseAdapter) {
Rectangle rect = new Rectangle(36, 36); int buttonSize = GUISizeHelper.gamePhaseButtonSize;
HoverButton button = new HoverButton("", ImageManagerImpl.instance.getPhaseImage(name), rect); Rectangle rect = new Rectangle(buttonSize, buttonSize);
HoverButton button = new HoverButton("", ImageManagerImpl.instance.getPhaseImage(name, buttonSize), rect);
button.setToolTipText(name.replaceAll("_", " ")); button.setToolTipText(name.replaceAll("_", " "));
button.setPreferredSize(new Dimension(36, 36)); button.setPreferredSize(new Dimension(buttonSize, buttonSize));
button.addMouseListener(mouseAdapter); button.addMouseListener(mouseAdapter);
phaseButtons.put(name, button); phaseButtons.put(name, button);
jPhases.add(button);
} }
// Event listener for the ShowCardsDialog // Event listener for the ShowCardsDialog
@ -3156,9 +3234,6 @@ public final class GamePanel extends javax.swing.JPanel {
private JPanel phasesContainer; private JPanel phasesContainer;
private javax.swing.JLabel txtHoldPriority; private javax.swing.JLabel txtHoldPriority;
private HoverButton currentStep;
private Point prevPoint;
private boolean imagePanelState; private boolean imagePanelState;
} }

View file

@ -370,9 +370,9 @@ public class PlayerPanelExt extends javax.swing.JPanel {
path = "/avatars/special/" + avatarId + ".gif"; path = "/avatars/special/" + avatarId + ".gif";
} }
Image image = ImageHelper.getImageFromResources(path); Image image = ImageHelper.getImageFromResources(path);
Rectangle r = new Rectangle(sizeMod(80), sizeMod(80)); Rectangle buttonRect = new Rectangle(sizeMod(80), sizeMod(80));
BufferedImage resized = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r); BufferedImage buttonImage = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), buttonRect);
this.avatar.update(this.player.getName(), resized, resized, resized, resized, r); this.avatar.update(this.player.getName(), buttonImage, buttonImage, buttonImage, buttonImage, buttonRect);
} }
} }
if (this.timer != null) { if (this.timer != null) {

View file

@ -50,10 +50,10 @@ public final class GUISizeHelper {
public static int gameFeedbackPanelExtraMessageFontSize = 11; public static int gameFeedbackPanelExtraMessageFontSize = 11;
public static int gameFeedbackPanelMaxHeight = 0; public static int gameFeedbackPanelMaxHeight = 0;
public static int gameDialogAreaButtonHigh = 16; public static int gamePhaseButtonSize = 36;
public static int gameCommandButtonHeight = 32;
public static Font gameFeedbackPanelFont = new java.awt.Font("Arial", 0, 12); public static Font gameFeedbackPanelFont = new java.awt.Font("Arial", 0, 12);
public static float gameDialogAreaDefaultFontSize = gameFeedbackPanelFont.getSize2D();
public static int gameFeedbackPanelButtonHeight; public static int gameFeedbackPanelButtonHeight;
public static int gameFeedbackPanelButtonWidth; public static int gameFeedbackPanelButtonWidth;
@ -132,6 +132,10 @@ public final class GUISizeHelper {
gameFeedbackPanelButtonHeight = dialogFontSize + 6; gameFeedbackPanelButtonHeight = dialogFontSize + 6;
gameFeedbackPanelButtonWidth = dialogFontSize * 2 + 40; gameFeedbackPanelButtonWidth = dialogFontSize * 2 + 40;
// game - phase and command buttons
gamePhaseButtonSize = dialogGuiScaleSize(36);
gameCommandButtonHeight = dialogGuiScaleSize(32);
// app - chats and game logs // app - chats and game logs
int chatFontSize = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_CHAT_FONT_SIZE, 14); int chatFontSize = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_CHAT_FONT_SIZE, 14);
chatFont = new java.awt.Font("Arial", 0, chatFontSize); chatFont = new java.awt.Font("Arial", 0, chatFontSize);

View file

@ -5,6 +5,11 @@ import mage.abilities.icon.CardIconColor;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
/**
* GUI: images source for GUI components like buttons. With theme supports.
*
* @author JayDi85
*/
public interface ImageManager { public interface ImageManager {
Image getAppImage(); Image getAppImage();
@ -57,29 +62,29 @@ public interface ImageManager {
Image getDlgActiveNextButtonImage(); Image getDlgActiveNextButtonImage();
Image getSwitchHandsButtonImage(); Image getSwitchHandsButtonImage(int height);
Image getStopWatchButtonImage(); Image getStopWatchButtonImage(int height);
Image getConcedeButtonImage(); Image getConcedeButtonImage(int height);
Image getCancelSkipButtonImage(); Image getCancelSkipButtonImage(int height);
Image getSkipNextTurnButtonImage(); Image getSkipNextTurnButtonImage(int height);
Image getSkipEndTurnButtonImage(); Image getSkipEndTurnButtonImage(int height);
Image getSkipMainButtonImage(); Image getSkipMainButtonImage(int height);
Image getSkipStackButtonImage(); Image getSkipStackButtonImage(int height);
Image getSkipEndStepBeforeYourTurnButtonImage(); Image getSkipEndStepBeforeYourTurnButtonImage(int height);
Image getSkipYourNextTurnButtonImage(); Image getSkipYourNextTurnButtonImage(int height);
Image getToggleRecordMacroButtonImage(); Image getToggleRecordMacroButtonImage(int height);
BufferedImage getCardIcon(String resourceName, int size, CardIconColor cardIconColor); BufferedImage getCardIcon(String resourceName, int size, CardIconColor cardIconColor);
Image getPhaseImage(String phase); Image getPhaseImage(String phase, int size);
} }

View file

@ -21,7 +21,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
* GUI plugin: images and icons with theme support * GUI: images source for GUI components like buttons. With theme supports.
* *
* @author JayDi85 * @author JayDi85
*/ */
@ -61,6 +61,7 @@ public enum ImageManagerImpl implements ImageManager {
private static final SoftValuesLoadingCache<Key, BufferedImage> THEME_BUTTON_IMAGES_CACHE; private static final SoftValuesLoadingCache<Key, BufferedImage> THEME_BUTTON_IMAGES_CACHE;
private static final SoftValuesLoadingCache<Key, Image> PHASE_THEME_BUTTON_IMAGES_CACHE; private static final SoftValuesLoadingCache<Key, Image> PHASE_THEME_BUTTON_IMAGES_CACHE;
static { static {
THEME_BUTTON_IMAGES_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(ImageManagerImpl::createThemeButtonImage)); THEME_BUTTON_IMAGES_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(ImageManagerImpl::createThemeButtonImage));
PHASE_THEME_BUTTON_IMAGES_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(ImageManagerImpl::createPhaseThemeButtonImage)); PHASE_THEME_BUTTON_IMAGES_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(ImageManagerImpl::createPhaseThemeButtonImage));
@ -69,15 +70,21 @@ public enum ImageManagerImpl implements ImageManager {
private static final class Key { private static final class Key {
final String resourceName; final String resourceName;
final int width;
final int height;
public Key(String resourceName) { public Key(String resourceName, int width, int height) {
this.resourceName = resourceName; this.resourceName = resourceName;
this.width = width;
this.height = height;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int hash = 3; int hash = 3;
hash = 53 * hash + Objects.hashCode(this.resourceName); hash = 53 * hash + Objects.hashCode(this.resourceName);
hash = 53 * hash + this.width;
hash = 53 * hash + this.height;
return hash; return hash;
} }
@ -96,31 +103,40 @@ public enum ImageManagerImpl implements ImageManager {
if (!this.resourceName.equals(other.resourceName)) { if (!this.resourceName.equals(other.resourceName)) {
return false; return false;
} }
if (this.width != other.width) {
return false;
}
if (this.height != other.height) {
return false;
}
return true; return true;
} }
} }
private static BufferedImage createThemeButtonImage(ImageManagerImpl.Key key) { private static BufferedImage createThemeButtonImage(ImageManagerImpl.Key key) {
return getBufferedImageFromResource(PreferencesDialog.getCurrentTheme().getButtonPath(key.resourceName)); String resName = PreferencesDialog.getCurrentTheme().getButtonPath(key.resourceName);
return getBufferedImageFromResource(resName, key.width, key.height);
} }
private static Image createPhaseThemeButtonImage(ImageManagerImpl.Key key) { private static Image createPhaseThemeButtonImage(ImageManagerImpl.Key key) {
return getImageFromResource( String resName = PreferencesDialog.getCurrentTheme().getPhasePath("phase_" + key.resourceName.toLowerCase(Locale.ENGLISH) + ".png");
PreferencesDialog.getCurrentTheme().getPhasePath("phase_" + key.resourceName.toLowerCase(Locale.ENGLISH) + ".png"), return getImageFromResource(resName, key.width, key.height);
new Rectangle(36, 36)
);
} }
ImageManagerImpl() { ImageManagerImpl() {
} }
public BufferedImage getThemeButton(String resourceName) { private BufferedImage getThemeButton(String resourceName, int height) {
return THEME_BUTTON_IMAGES_CACHE.getOrThrow(new ImageManagerImpl.Key(resourceName)); // all command buttons are 64 x 32
// TODO: add theme support with any proportion buttons
return THEME_BUTTON_IMAGES_CACHE.getOrThrow(new ImageManagerImpl.Key(resourceName, 2 * height, height));
} }
@Override @Override
public Image getPhaseImage(String phaseName) { public Image getPhaseImage(String phaseName, int size) {
return PHASE_THEME_BUTTON_IMAGES_CACHE.getOrThrow(new ImageManagerImpl.Key(phaseName)); // all phase buttons are 36 x 36
// TODO: add theme support with any proportion buttons
return PHASE_THEME_BUTTON_IMAGES_CACHE.getOrThrow(new ImageManagerImpl.Key(phaseName, size, size));
} }
@Override @Override
@ -344,58 +360,58 @@ public enum ImageManagerImpl implements ImageManager {
} }
@Override @Override
public Image getConcedeButtonImage() { public Image getConcedeButtonImage(int height) {
return getThemeButton("concede.png"); return getThemeButton("concede.png", height);
} }
@Override @Override
public Image getSwitchHandsButtonImage() { public Image getSwitchHandsButtonImage(int height) {
return getThemeButton("switch_hands.png"); return getThemeButton("switch_hands.png", height);
} }
@Override @Override
public Image getStopWatchButtonImage() { public Image getStopWatchButtonImage(int height) {
return getThemeButton("stop_watching.png"); return getThemeButton("stop_watching.png", height);
} }
@Override @Override
public Image getCancelSkipButtonImage() { public Image getCancelSkipButtonImage(int height) {
return getThemeButton("cancel_skip.png"); return getThemeButton("cancel_skip.png", height);
} }
@Override @Override
public Image getSkipNextTurnButtonImage() { public Image getSkipNextTurnButtonImage(int height) {
return getThemeButton("skip_turn.png"); return getThemeButton("skip_turn.png", height);
} }
@Override @Override
public Image getSkipEndTurnButtonImage() { public Image getSkipEndTurnButtonImage(int height) {
return getThemeButton("skip_to_end.png"); return getThemeButton("skip_to_end.png", height);
} }
@Override @Override
public Image getSkipMainButtonImage() { public Image getSkipMainButtonImage(int height) {
return getThemeButton("skip_to_main.png"); return getThemeButton("skip_to_main.png", height);
} }
@Override @Override
public Image getSkipStackButtonImage() { public Image getSkipStackButtonImage(int height) {
return getThemeButton("skip_stack.png"); return getThemeButton("skip_stack.png", height);
} }
@Override @Override
public Image getSkipEndStepBeforeYourTurnButtonImage() { public Image getSkipEndStepBeforeYourTurnButtonImage(int height) {
return getThemeButton("skip_to_previous_end.png"); return getThemeButton("skip_to_previous_end.png", height);
} }
@Override @Override
public Image getSkipYourNextTurnButtonImage() { public Image getSkipYourNextTurnButtonImage(int height) {
return getThemeButton("skip_all.png"); return getThemeButton("skip_all.png", height);
} }
@Override @Override
public Image getToggleRecordMacroButtonImage() { public Image getToggleRecordMacroButtonImage(int height) {
return getThemeButton("toggle_macro.png"); return getThemeButton("toggle_macro.png", height);
} }
@Override @Override
@ -414,51 +430,62 @@ public enum ImageManagerImpl implements ImageManager {
} }
} }
protected static Image getImageFromResourceTransparent(String path, Color mask, Rectangle rec) { private static Image getImageFromResourceTransparent(String path, Color mask, Rectangle rec) {
BufferedImage image; Image res = null;
Image imageCardTransparent;
Image resized = null;
URL imageURL = ImageManager.class.getResource(path); URL imageURL = ImageManager.class.getResource(path);
try { try {
image = ImageIO.read(imageURL); BufferedImage original = ImageIO.read(imageURL);
imageCardTransparent = Transparency.makeColorTransparent(image, mask); Image transparent = Transparency.makeColorTransparent(original, mask);
res = transparent.getScaledInstance(rec.width, rec.height, java.awt.Image.SCALE_SMOOTH);
resized = imageCardTransparent.getScaledInstance(rec.width, rec.height, java.awt.Image.SCALE_SMOOTH);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
return resized; return res;
} }
protected static Image getImageFromResource(String path, Rectangle rec) { private static Image getImageFromResource(String path) {
Image resized = null; return getImageFromResource(path, 0, 0);
}
private static Image getImageFromResource(String path, int width, int height) {
Image res = null;
URL imageURL = ImageManager.class.getResource(path); URL imageURL = ImageManager.class.getResource(path);
try { try {
BufferedImage image = ImageIO.read(imageURL); BufferedImage image = ImageIO.read(imageURL);
resized = image.getScaledInstance(rec.width, rec.height, java.awt.Image.SCALE_SMOOTH); if (width > 0 && height > 0) {
// use new size
res = image.getScaledInstance(width, height, java.awt.Image.SCALE_SMOOTH);
} else {
// keep file size
res = image;
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
return resized; return res;
} }
protected static BufferedImage getBufferedImageFromResource(String path) { private static BufferedImage getBufferedImageFromResource(String path) {
URL imageURL = ImageManager.class.getResource(path); return getBufferedImageFromResource(path, 0, 0);
BufferedImage image = null; }
private static BufferedImage getBufferedImageFromResource(String path, int width, int height) {
Image original = getImageFromResource(path, width, height);
BufferedImage output = new BufferedImage(original.getWidth(null), original.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = output.createGraphics();
try { try {
image = ImageIO.read(imageURL); g2.drawImage(original, 0, 0, null);
} catch (Exception e) { } finally {
e.printStackTrace(); g2.dispose();
} }
return image; return output;
} }
public static BufferedImage deepCopy(BufferedImage bi) { public static BufferedImage deepCopy(BufferedImage bi) {

View file

@ -35,6 +35,8 @@ public class DebugUtil {
public static boolean GUI_GAME_DRAW_BATTLEFIELD_BORDER = false; public static boolean GUI_GAME_DRAW_BATTLEFIELD_BORDER = false;
public static boolean GUI_GAME_DRAW_HAND_AND_STACK_BORDER = false; public static boolean GUI_GAME_DRAW_HAND_AND_STACK_BORDER = false;
public static boolean GUI_GAME_DRAW_PLAYER_PANEL_BORDER = false; public static boolean GUI_GAME_DRAW_PLAYER_PANEL_BORDER = false;
public static boolean GUI_GAME_DRAW_COMMAND_BUTTONS_PANEL_BORDER = false;
public static boolean GUI_GAME_DRAW_PHASE_BUTTONS_PANEL_BORDER = false;
// game dialogs // game dialogs
public static boolean GUI_GAME_DIALOGS_DRAW_CARDS_AREA_BORDER = false; public static boolean GUI_GAME_DIALOGS_DRAW_CARDS_AREA_BORDER = false;