diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml
index 9ab3cec792..7c96a42190 100644
--- a/Mage.Client/pom.xml
+++ b/Mage.Client/pom.xml
@@ -161,6 +161,11 @@
prettytime
4.0.2.Final
+
+ org.unbescape
+ unbescape
+ 1.1.6.RELEASE
+
diff --git a/Mage.Client/sounds/FeedbackNeeded.wav b/Mage.Client/sounds/FeedbackNeeded.wav
new file mode 100644
index 0000000000..be64080145
Binary files /dev/null and b/Mage.Client/sounds/FeedbackNeeded.wav differ
diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java
index 520014b62d..b65dfe74f3 100644
--- a/Mage.Client/src/main/java/mage/client/MageFrame.java
+++ b/Mage.Client/src/main/java/mage/client/MageFrame.java
@@ -200,9 +200,17 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
TConfig config = TConfig.current();
config.setArchiveDetector(new TArchiveDetector("zip"));
config.setAccessPreference(FsAccessOption.STORE, true);
+
try {
UIManager.put("desktop", new Color(0, 0, 0, 0));
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
+
+ UIManager.put("nimbusBlueGrey", PreferencesDialog.getCurrentTheme().getNimbusBlueGrey()); // buttons, scrollbar background, disabled inputs
+ UIManager.put("control", PreferencesDialog.getCurrentTheme().getControl()); // window bg
+ UIManager.put("nimbusLightBackground", PreferencesDialog.getCurrentTheme().getNimbusLightBackground()); // inputs, table rows
+ UIManager.put("info", PreferencesDialog.getCurrentTheme().getInfo()); // tooltips
+ UIManager.put("nimbusBase", PreferencesDialog.getCurrentTheme().getNimbusBase()); // title bars, scrollbar foreground
+
//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// stop JSplitPane from eating F6 and F8 or any other function keys
{
@@ -445,16 +453,19 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
+ // Sets background for login screen
private void setBackground() {
if (liteMode || grayMode) {
return;
}
- String filename = "/background.jpg";
+
try {
- if (Plugins.instance.isThemePluginLoaded()) {
+ // If user has custom background, use that, otherwise, use theme background
+ if (Plugins.instance.isThemePluginLoaded() &&
+ !PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BACKGROUND_IMAGE_DEFAULT, "true").equals("true")) {
backgroundPane = (ImagePanel) Plugins.instance.updateTablePanel(new HashMap<>());
} else {
- InputStream is = this.getClass().getResourceAsStream(filename);
+ InputStream is = this.getClass().getResourceAsStream(PreferencesDialog.getCurrentTheme().getLoginBackgroundPath());
BufferedImage background = ImageIO.read(is);
backgroundPane = new ImagePanel(background, ImagePanelStyle.SCALED);
}
@@ -1020,6 +1031,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
.addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 145, Short.MAX_VALUE))
);
+ if (PreferencesDialog.getCurrentTheme().getMageToolbar() != null) {
+ mageToolbar.getParent().setBackground(PreferencesDialog.getCurrentTheme().getMageToolbar());
+ }
+
pack();
}// //GEN-END:initComponents
diff --git a/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java
index c58ae3cad2..0054cb51d7 100644
--- a/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java
+++ b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java
@@ -12,41 +12,48 @@ import mage.client.dialog.PreferencesDialog;
*/
public class KeyboundButton extends JButton {
- private final String text;
- private static final Font keyFont = new Font(Font.SANS_SERIF, Font.BOLD, 13);
+ private final String text;
+ private static final Font keyFont = new Font(Font.SANS_SERIF, Font.BOLD, 13);
- private boolean tinting = false;
+ private boolean tinting = false;
- public KeyboundButton(String key) {
- text = PreferencesDialog.getCachedKeyText(key);
- }
+ public KeyboundButton(String key, boolean drawText) {
+ if (drawText) {
+ text = PreferencesDialog.getCachedKeyText(key);
+ } else {
+ text = "";
+ }
+ }
- @Override
- protected void paintComponent(Graphics g) {
- if (ui != null && g != null) {
- Graphics sg = g.create();
- try {
- ui.update(sg, this);
- if (tinting) {
- sg.setColor(new Color(0, 0, 0, 32));
- sg.fillRoundRect(2, 2, getWidth() - 4 , getHeight() - 4, 6, 6);
- }
- sg.setColor(tinting ? Color.lightGray : Color.white);
- sg.setFont(keyFont);
+ @Override
+ protected void paintComponent(Graphics g) {
+ if (ui != null && g != null) {
+ Graphics sg = g.create();
+ try {
+ ui.update(sg, this);
- int textWidth = sg.getFontMetrics(keyFont).stringWidth(text);
- int centerX = (getWidth() - textWidth) / 2;
+ if (tinting) {
+ sg.setColor(new Color(0, 0, 0, 32));
+ sg.fillRoundRect(2, 2, getWidth() - 4 , getHeight() - 4, 6, 6);
+ }
+ sg.setColor(tinting ? Color.lightGray : Color.white);
- sg.drawString(text, centerX, 28);
- } finally {
- sg.dispose();
- }
- }
- }
+ if (!text.isEmpty()) {
+ sg.setFont(keyFont);
- public void setTint(boolean tinting) {
- this.tinting = tinting;
- repaint();
- }
+ int textWidth = sg.getFontMetrics(keyFont).stringWidth(text);
+ int centerX = (getWidth() - textWidth) / 2;
+ sg.drawString(text, centerX, 28);
+ }
+ } finally {
+ sg.dispose();
+ }
+ }
+ }
+
+ public void setTint(boolean tinting) {
+ this.tinting = tinting;
+ repaint();
+ }
}
diff --git a/Mage.Client/src/main/java/mage/client/components/LegalityLabel.java b/Mage.Client/src/main/java/mage/client/components/LegalityLabel.java
new file mode 100644
index 0000000000..ab711cc42a
--- /dev/null
+++ b/Mage.Client/src/main/java/mage/client/components/LegalityLabel.java
@@ -0,0 +1,180 @@
+package mage.client.components;
+
+import mage.cards.decks.Deck;
+import mage.cards.decks.DeckValidator;
+import mage.cards.decks.importer.DeckImporter;
+import org.unbescape.html.HtmlEscape;
+import org.unbescape.html.HtmlEscapeLevel;
+import org.unbescape.html.HtmlEscapeType;
+
+import javax.swing.*;
+import java.awt.*;
+import java.io.File;
+import java.util.Map;
+
+/**
+ * @author Elandril
+ */
+public class LegalityLabel extends JLabel {
+
+ protected static final Color COLOR_UNKNOWN = new Color(174, 174, 174);
+ protected static final Color COLOR_LEGAL = new Color(117, 152, 110);
+ protected static final Color COLOR_NOT_LEGAL = new Color(191, 84, 74);
+ protected static final Color COLOR_TEXT = new Color(255, 255, 255);
+ protected static final Dimension DIM_MINIMUM = new Dimension(75, 25);
+ protected static final Dimension DIM_MAXIMUM = new Dimension(150, 75);
+ protected static final Dimension DIM_PREFERRED = new Dimension(75, 25);
+
+ protected Deck currentDeck;
+ protected String errorMessage;
+ protected DeckValidator validator;
+
+ /**
+ * Creates a LegalityLabel
instance with the specified text
+ * and the given DeckValidator.
+ *
+ * @param text The text to be displayed by the label.
+ * @param validator The DeckValidator to check against.
+ */
+ public LegalityLabel(String text, DeckValidator validator) {
+ super(text);
+ this.validator = validator;
+
+ setBackground(COLOR_UNKNOWN);
+ setForeground(COLOR_TEXT);
+ setHorizontalAlignment(SwingConstants.CENTER);
+ setMinimumSize(DIM_MINIMUM);
+ setMaximumSize(DIM_MAXIMUM);
+ setName(text); // NOI18N
+ setOpaque(true);
+ setPreferredSize(DIM_PREFERRED);
+ }
+
+ /**
+ * Creates a LegalityLabel
instance with the given DeckValidator and uses its
+ * shortName as the text.
+ *
+ * @param validator The DeckValidator to check against.
+ */
+ public LegalityLabel(DeckValidator validator) {
+ this(validator.getShortName(), validator);
+ }
+
+ /**
+ * Creates a LegalityLabel
instance with no DeckValidator or text.
+ * This is used by the Netbeans GUI Editor.
+ */
+ public LegalityLabel() {
+ super();
+
+ setBackground(COLOR_UNKNOWN);
+ setForeground(COLOR_TEXT);
+ setHorizontalAlignment(SwingConstants.CENTER);
+ setMinimumSize(DIM_MINIMUM);
+ setMaximumSize(DIM_MAXIMUM);
+ setOpaque(true);
+ setPreferredSize(DIM_PREFERRED);
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public DeckValidator getValidator() {
+ return validator;
+ }
+
+ public void setValidator(DeckValidator validator) {
+ this.validator = validator;
+ revalidateDeck();
+ }
+
+ protected String escapeHtml(String string) {
+ return HtmlEscape.escapeHtml(string, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA, HtmlEscapeLevel.LEVEL_0_ONLY_MARKUP_SIGNIFICANT_EXCEPT_APOS);
+ }
+
+ protected String formatInvalidTooltip(Map invalid) {
+ return invalid.entrySet().stream()
+ .sorted(Map.Entry.comparingByKey())
+ .reduce("Deck is INVALID
The following problems have been found:
",
+ (str, entry) -> String.format("%s%s | %s |
", str, escapeHtml(entry.getKey()), escapeHtml(entry.getValue())), String::concat)
+ + "
";
+ }
+
+ private String appendErrorMessage(String string) {
+ if (errorMessage.isEmpty())
+ return string;
+ if (string.contains("")) {
+ return string.replaceFirst("(()?