diff --git a/Mage.Client/src/main/java/mage/client/components/ColorPane.java b/Mage.Client/src/main/java/mage/client/components/ColorPane.java index 93546310655..86acc499160 100644 --- a/Mage.Client/src/main/java/mage/client/components/ColorPane.java +++ b/Mage.Client/src/main/java/mage/client/components/ColorPane.java @@ -1,158 +1,17 @@ package mage.client.components; -import mage.cards.action.TransferData; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.client.MageFrame; -import mage.client.cards.BigCard; -import mage.client.cards.VirtualCardInfo; -import mage.client.dialog.PreferencesDialog; -import mage.client.game.GamePanel; -import mage.game.command.Plane; -import mage.util.CardUtil; -import mage.util.GameLog; -import mage.utils.ThreadUtils; -import mage.view.CardView; -import mage.view.PlaneView; - import javax.swing.*; -import javax.swing.event.HyperlinkEvent.EventType; -import javax.swing.text.SimpleAttributeSet; -import javax.swing.text.html.HTMLDocument; -import javax.swing.text.html.HTMLEditorKit; import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.*; /** - * GUI: chats with html and hints popup support for objects + * GUI: component for display chats and game logs. Support html, mana symbols and popups. * * @author nantuko, JayDi85 */ -public class ColorPane extends JEditorPane { - - final HTMLEditorKit kit = new HTMLEditorKit(); - final HTMLDocument doc = new HTMLDocument(); - - private static final int CHAT_TOOLTIP_DELAY_MS = 50; // cards popup from chat must be fast all time - - // cards popup info - private boolean hyperlinkEnabled = false; - VirtualCardInfo cardInfo = new VirtualCardInfo(); - UUID gameId = null; - BigCard bigCard = null; - +public class ColorPane extends MageEditorPane { public ColorPane() { - this.setEditorKit(kit); - this.setDocument(doc); - } - - private void addHyperlinkHandlers() { - if (Arrays.stream(getHyperlinkListeners()).findAny().isPresent()) { - throw new IllegalStateException("Wrong code usage: popup links support enabled already"); - } - addHyperlinkListener(e -> ThreadUtils.threadPoolPopups.submit(() -> { - if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_DELAY, 300) == 0) { - // if disabled - return; - } - - // finds extra data in html element like object_id, alternative_name, etc - Map extraData = new HashMap<>(); - if (e.getSourceElement() instanceof HTMLDocument.RunElement) { - HTMLDocument.RunElement el = (HTMLDocument.RunElement) e.getSourceElement(); - Enumeration attNames = el.getAttributeNames(); - while (attNames.hasMoreElements()) { - Object attName = attNames.nextElement(); - Object attValue = el.getAttribute(attName); - // custom attributes in SimpleAttributeSet element - if (attValue instanceof SimpleAttributeSet) { - SimpleAttributeSet attReal = (SimpleAttributeSet) attValue; - Enumeration attRealNames = attReal.getAttributeNames(); - while (attRealNames.hasMoreElements()) { - Object attRealName = attRealNames.nextElement(); - Object attRealValue = attReal.getAttribute(attRealName); - String name = attRealName.toString(); - String value = attRealValue.toString(); - extraData.put(name, value); - } - } - } - } - - // try object first - CardView needCard = null; - GamePanel gamePanel = MageFrame.getGame(this.gameId); - if (gamePanel != null) { - UUID needObjectId = UUID.fromString(extraData.getOrDefault("object_id", "")); - needCard = gamePanel.getLastGameData().findCard(needObjectId); - } - - String cardName = e.getDescription().substring(1); - String alternativeName = CardUtil.urlDecode(extraData.getOrDefault("alternative_name", "")); - if (!alternativeName.isEmpty()) { - cardName = alternativeName; - } - - if (e.getEventType() == EventType.ENTERED) { - // show real object by priority (workable card hints and actual info) - CardView cardView = needCard; - - // if no game object found then show default card - if (cardView == null) { - CardInfo card = CardRepository.instance.findCards(cardName).stream().findFirst().orElse(null); - if (card != null) { - cardView = new CardView(card.getMockCard()); - } - } - - // plane - if (cardView == null) { - Plane plane = Plane.createPlaneByFullName(cardName); - if (plane != null) { - cardView = new CardView(new PlaneView(plane)); - } - } - - // TODO: add other objects like dungeon, emblem, commander - - if (cardView != null) { - cardInfo.init(cardView, this.bigCard, this.gameId); - cardInfo.setTooltipDelay(CHAT_TOOLTIP_DELAY_MS); - cardInfo.setPopupAutoLocationMode(TransferData.PopupAutoLocationMode.PUT_NEAR_MOUSE_POSITION); - SwingUtilities.invokeLater(() -> { - cardInfo.onMouseEntered(MouseInfo.getPointerInfo().getLocation()); - cardInfo.onMouseMoved(MouseInfo.getPointerInfo().getLocation()); - }); - } - } - - if (e.getEventType() == EventType.ACTIVATED) { - SwingUtilities.invokeLater(() -> { - cardInfo.onMouseWheel(MouseInfo.getPointerInfo().getLocation()); - }); - } - - if (e.getEventType() == EventType.EXITED) { - SwingUtilities.invokeLater(() -> { - cardInfo.onMouseExited(); - }); - } - })); - - addMouseListener(new MouseAdapter() { - @Override - public void mouseExited(MouseEvent e) { - cardInfo.onMouseExited(); - } - }); - } - - public void setGameData(UUID gameId, BigCard bigCard) { - this.gameId = gameId; - this.bigCard = bigCard; + super(); } /** @@ -169,26 +28,6 @@ public class ColorPane extends JEditorPane { add(jPanel); } - @Override - public void setText(String text) { - // must use append to enable popup/hyperlinks support - super.setText(""); - append(text); - } - - public void append(String text) { - try { - if (hyperlinkEnabled) { - text = GameLog.injectPopupSupport(text); - } - kit.insertHTML(doc, doc.getLength(), text, 0, 0, null); - int len = getDocument().getLength(); - setCaretPosition(len); - } catch (Exception e) { - e.printStackTrace(); - } - } - /** * A little trick to paint black background under the text. * @@ -208,10 +47,4 @@ public class ColorPane extends JEditorPane { public void paintComponent(Graphics g) { super.paintChildren(g); } - - public void enableHyperlinksAndCardPopups() { - hyperlinkEnabled = true; - addHyperlinkHandlers(); - } - } diff --git a/Mage.Client/src/main/java/mage/client/components/MageEditorPane.java b/Mage.Client/src/main/java/mage/client/components/MageEditorPane.java new file mode 100644 index 00000000000..76c39f0d92f --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/MageEditorPane.java @@ -0,0 +1,183 @@ +package mage.client.components; + +import mage.cards.action.TransferData; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.client.MageFrame; +import mage.client.cards.BigCard; +import mage.client.cards.VirtualCardInfo; +import mage.client.dialog.PreferencesDialog; +import mage.client.game.GamePanel; +import mage.game.command.Plane; +import mage.util.CardUtil; +import mage.util.GameLog; +import mage.utils.ThreadUtils; +import mage.view.CardView; +import mage.view.PlaneView; + +import javax.swing.*; +import javax.swing.event.HyperlinkEvent; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.HTMLEditorKit; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.*; + +/** + * GUI: improved editor pane with html, hyperlinks/popup support + * + * @author JayDi85 + */ +public class MageEditorPane extends JEditorPane { + + private static final int CHAT_TOOLTIP_DELAY_MS = 50; // cards popup from chat must be fast all time + final HTMLEditorKit kit = new HTMLEditorKit(); + final HTMLDocument doc; + + MageEditorPane() { + super(); + // merge with UI.setHTMLEditorKit + this.setEditorKit(kit); + this.doc = (HTMLDocument) this.getDocument(); // HTMLEditorKit must creates HTMLDocument, os use it here + } + + // cards popup info + private boolean hyperlinkEnabled = false; + VirtualCardInfo cardInfo = new VirtualCardInfo(); + UUID gameId = null; + BigCard bigCard = null; + + public void setGameData(UUID gameId, BigCard bigCard) { + this.gameId = gameId; + this.bigCard = bigCard; + } + + private void addHyperlinkHandlers() { + if (Arrays.stream(getHyperlinkListeners()).findAny().isPresent()) { + throw new IllegalStateException("Wrong code usage: popup links support enabled already"); + } + addHyperlinkListener(e -> ThreadUtils.threadPoolPopups.submit(() -> { + if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_DELAY, 300) == 0) { + // if disabled + return; + } + + // finds extra data in html element like object_id, alternative_name, etc + Map extraData = new HashMap<>(); + if (e.getSourceElement() instanceof HTMLDocument.RunElement) { + HTMLDocument.RunElement el = (HTMLDocument.RunElement) e.getSourceElement(); + Enumeration attNames = el.getAttributeNames(); + while (attNames.hasMoreElements()) { + Object attName = attNames.nextElement(); + Object attValue = el.getAttribute(attName); + // custom attributes in SimpleAttributeSet element + if (attValue instanceof SimpleAttributeSet) { + SimpleAttributeSet attReal = (SimpleAttributeSet) attValue; + Enumeration attRealNames = attReal.getAttributeNames(); + while (attRealNames.hasMoreElements()) { + Object attRealName = attRealNames.nextElement(); + Object attRealValue = attReal.getAttribute(attRealName); + String name = attRealName.toString(); + String value = attRealValue.toString(); + extraData.put(name, value); + } + } + } + } + + // try object first + CardView needCard = null; + GamePanel gamePanel = MageFrame.getGame(this.gameId); + if (gamePanel != null) { + UUID needObjectId = UUID.fromString(extraData.getOrDefault("object_id", "")); + needCard = gamePanel.getLastGameData().findCard(needObjectId); + } + + String cardName = e.getDescription().substring(1); + String alternativeName = CardUtil.urlDecode(extraData.getOrDefault("alternative_name", "")); + if (!alternativeName.isEmpty()) { + cardName = alternativeName; + } + + if (e.getEventType() == HyperlinkEvent.EventType.ENTERED) { + // show real object by priority (workable card hints and actual info) + CardView cardView = needCard; + + // if no game object found then show default card + if (cardView == null) { + CardInfo card = CardRepository.instance.findCards(cardName).stream().findFirst().orElse(null); + if (card != null) { + cardView = new CardView(card.getMockCard()); + } + } + + // plane + if (cardView == null) { + Plane plane = Plane.createPlaneByFullName(cardName); + if (plane != null) { + cardView = new CardView(new PlaneView(plane)); + } + } + + // TODO: add other objects like dungeon, emblem, commander + + if (cardView != null) { + cardInfo.init(cardView, this.bigCard, this.gameId); + cardInfo.setTooltipDelay(CHAT_TOOLTIP_DELAY_MS); + cardInfo.setPopupAutoLocationMode(TransferData.PopupAutoLocationMode.PUT_NEAR_MOUSE_POSITION); + SwingUtilities.invokeLater(() -> { + cardInfo.onMouseEntered(MouseInfo.getPointerInfo().getLocation()); + cardInfo.onMouseMoved(MouseInfo.getPointerInfo().getLocation()); + }); + } + } + + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + SwingUtilities.invokeLater(() -> { + cardInfo.onMouseWheel(MouseInfo.getPointerInfo().getLocation()); + }); + } + + if (e.getEventType() == HyperlinkEvent.EventType.EXITED) { + SwingUtilities.invokeLater(() -> { + cardInfo.onMouseExited(); + }); + } + })); + + addMouseListener(new MouseAdapter() { + // TODO: add popup mouse wheel here? + @Override + public void mouseExited(MouseEvent e) { + cardInfo.onMouseExited(); + } + }); + } + + @Override + public void setText(String text) { + // must use append to enable popup/hyperlinks support + super.setText(""); + append(text); + } + + public void append(String text) { + try { + if (hyperlinkEnabled) { + text = GameLog.injectPopupSupport(text); + } + kit.insertHTML(doc, doc.getLength(), text, 0, 0, null); + int len = getDocument().getLength(); + setCaretPosition(len); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void enableHyperlinksAndCardPopups() { + hyperlinkEnabled = true; + addHyperlinkHandlers(); + } +} diff --git a/Mage.Client/src/main/java/mage/client/components/MageTextArea.java b/Mage.Client/src/main/java/mage/client/components/MageTextArea.java index 6928297878e..5e4109819cf 100644 --- a/Mage.Client/src/main/java/mage/client/components/MageTextArea.java +++ b/Mage.Client/src/main/java/mage/client/components/MageTextArea.java @@ -8,19 +8,21 @@ import org.mage.card.arcane.ManaSymbols; import org.mage.card.arcane.UI; /** - * Component for displaying text in mage. Supports drawing mana symbols. + * GUI: component for displaying text in feedback panel. Support html, mana symbols and popups. * * @author nantuko */ -public class MageTextArea extends JEditorPane { +public class MageTextArea extends MageEditorPane { + private String currentText; private int currentPanelWidth; public MageTextArea() { - UI.setHTMLEditorKit(this); + super(); setEditable(false); setBackground(new Color(0, 0, 0, 0)); // transparent background setFocusable(false); + enableHyperlinksAndCardPopups(); } @Override @@ -32,16 +34,18 @@ public class MageTextArea extends JEditorPane { if (text == null) { return; } - - if(text.equals(currentText) && panelWidth == currentPanelWidth) + if (text.equals(currentText) && panelWidth == currentPanelWidth) { return; + } currentText = text; currentPanelWidth = panelWidth; + // prepare text format as header and details texts + final StringBuilder buffer = new StringBuilder(512); // Dialog is a java logical font family, so it should work on all systems - buffer.append("
"); @@ -54,11 +58,11 @@ public class MageTextArea extends JEditorPane { if (!text.isEmpty()) { buffer.append(basicText); } - buffer.append("
"); SwingUtilities.invokeLater(() -> { String promptText = buffer.toString(); + System.out.println(promptText); MageTextArea.super.setText(promptText); // in case the text don't fit in the panel a tooltip with the text is added if (panelWidth > 0 && MageTextArea.this.getPreferredSize().getWidth() > panelWidth) {