GUI: added card hint popup support in pick choice dialogs (dialogs with searchable list, related to #12420)

This commit is contained in:
Oleg Agafonov 2024-07-07 11:39:17 +04:00
parent fad0271dbf
commit f3db9cb8af
3 changed files with 95 additions and 77 deletions

View file

@ -25,6 +25,14 @@ import java.util.*;
/** /**
* GUI: improved editor pane with html, hyperlinks/popup support * GUI: improved editor pane with html, hyperlinks/popup support
* <p>
* Can be used as:
* - read only text panel (example: chats and game logs)
* - read only text label (example: header messages in choice dialogs)
* <p>
* Call in form's constructor or show dialog:
* - xxx.enableTextLabelMode to enable text label mode
* - xxx.enableHyperlinksAndCardPopups + xxx.setGameData to enable card popup support
* *
* @author JayDi85 * @author JayDi85
*/ */
@ -36,7 +44,6 @@ public class MageEditorPane extends JEditorPane {
final HTMLEditorKit kit = new HTMLEditorKit(); final HTMLEditorKit kit = new HTMLEditorKit();
final HTMLDocument doc; final HTMLDocument doc;
public MageEditorPane() { public MageEditorPane() {
super(); super();
// merge with UI.setHTMLEditorKit // merge with UI.setHTMLEditorKit
@ -47,6 +54,17 @@ public class MageEditorPane extends JEditorPane {
kit.getStyleSheet().addRule(" a { text-decoration: none; } "); kit.getStyleSheet().addRule(" a { text-decoration: none; } ");
} }
/**
* Simulate JLabel (non-editable and transparent background)
*/
public void enableTextLabelMode() {
this.setOpaque(false);
this.setFocusable(false);
this.setBorder(null);
this.setAutoscrolls(false);
this.setBackground(new Color(0, 0, 0, 0)); // transparent background
}
// cards popup info // cards popup info
private boolean hyperlinkEnabled = false; private boolean hyperlinkEnabled = false;
VirtualCardInfo cardInfo = new VirtualCardInfo(); VirtualCardInfo cardInfo = new VirtualCardInfo();

View file

@ -23,14 +23,14 @@
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="scrollList" alignment="1" max="32767" attributes="0"/> <Component id="scrollList" alignment="1" max="32767" attributes="0"/>
<Component id="panelCommands" alignment="0" max="32767" attributes="0"/> <Component id="panelCommands" alignment="0" max="32767" attributes="0"/>
<Component id="panelHeader" alignment="0" max="32767" attributes="0"/> <Component id="panelHeader" alignment="0" pref="371" max="32767" attributes="0"/>
<Component id="panelSearch" alignment="1" max="32767" attributes="0"/> <Component id="panelSearch" alignment="1" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -42,7 +42,7 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="panelSearch" min="-2" max="-2" attributes="0"/> <Component id="panelSearch" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="scrollList" pref="282" max="32767" attributes="0"/> <Component id="scrollList" pref="268" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="panelCommands" min="-2" max="-2" attributes="0"/> <Component id="panelCommands" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
@ -53,46 +53,41 @@
<SubComponents> <SubComponents>
<Container class="javax.swing.JPanel" name="panelHeader"> <Container class="javax.swing.JPanel" name="panelHeader">
<Layout> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="labelMessage" alignment="1" pref="337" max="32767" attributes="0"/>
<Component id="labelSubMessage" alignment="1" pref="337" max="32767" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="labelMessage" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="labelSubMessage" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents> <SubComponents>
<Component class="javax.swing.JLabel" name="labelMessage"> <Component class="mage.client.components.MageEditorPane" name="textMessage">
<Properties> <Properties>
<Property name="horizontalAlignment" type="int" value="0"/> <Property name="editable" type="boolean" value="false"/>
<Property name="text" type="java.lang.String" value="&lt;html&gt;&lt;div style=&apos;text-align: center;&apos;&gt;example long message example long message example long message example long message example long message&lt;/div&gt;&lt;/html&gt;"/> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
</Properties> <Border info="null"/>
</Component>
<Component class="javax.swing.JLabel" name="labelSubMessage">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="true" component="labelSubMessage" italic="true" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property> </Property>
<Property name="horizontalAlignment" type="int" value="0"/> <Property name="text" type="java.lang.String" value="&lt;html&gt;&lt;div style=&apos;text-align: center;&apos;&gt;example long message example long message example long message example long message example long message&lt;/div&gt;&lt;/html&gt;"/>
<Property name="text" type="java.lang.String" value="&lt;html&gt;&lt;div style=&apos;text-align: center;&apos;&gt;example long message example long&lt;/div&gt;&lt;/html&gt;"/> <Property name="autoscrolls" type="boolean" value="false"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="opaque" type="boolean" value="false"/>
</Properties> </Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
</Component>
<Component class="mage.client.components.MageEditorPane" name="textSubMessage">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
<Property name="text" type="java.lang.String" value="&lt;html&gt;&lt;div style=&apos;text-align: center;&apos;&gt;example long message example long&lt;/div&gt;&lt;/html&gt;"/>
<Property name="autoscrolls" type="boolean" value="false"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="opaque" type="boolean" value="false"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="South"/>
</Constraint>
</Constraints>
</Component> </Component>
</SubComponents> </SubComponents>
</Container> </Container>

View file

@ -13,6 +13,7 @@ import mage.choices.ChoiceHintType;
import mage.client.MageFrame; import mage.client.MageFrame;
import mage.client.cards.BigCard; import mage.client.cards.BigCard;
import mage.client.cards.VirtualCardInfo; import mage.client.cards.VirtualCardInfo;
import mage.client.components.MageEditorPane;
import mage.client.util.gui.MageDialogState; import mage.client.util.gui.MageDialogState;
import mage.game.command.Dungeon; import mage.game.command.Dungeon;
import mage.view.CardView; import mage.view.CardView;
@ -47,10 +48,13 @@ public class PickChoiceDialog extends MageDialog {
this.bigCard = bigCard; this.bigCard = bigCard;
this.gameId = objectId; this.gameId = objectId;
setLabelText(this.labelMessage, choice.getMessage()); setMessageText(this.textMessage, choice.getMessage(), false);
setLabelText(this.labelSubMessage, choice.getSubMessage()); setMessageText(this.textSubMessage, choice.getSubMessage(), true);
btCancel.setEnabled(!choice.isRequired()); btCancel.setEnabled(!choice.isRequired());
// popup support in headers
// special choice (example: auto-choose answer next time) // special choice (example: auto-choose answer next time)
cbSpecial.setVisible(choice.isSpecialEnabled()); cbSpecial.setVisible(choice.isSpecialEnabled());
cbSpecial.setText(choice.getSpecialText()); cbSpecial.setText(choice.getSpecialText());
@ -311,13 +315,16 @@ public class PickChoiceDialog extends MageDialog {
} }
} }
private void setLabelText(JLabel label, String text) { private void setMessageText(MageEditorPane editor, String text, boolean useBoldFont) {
editor.setGameData(this.gameId, this.bigCard);
if ((text != null) && !text.equals("")) { if ((text != null) && !text.equals("")) {
label.setText(String.format(HTML_HEADERS_TEMPLATE, text)); String realText = useBoldFont ? "<b>" + text + "<b>" : text;
label.setVisible(true); editor.setText(String.format(HTML_HEADERS_TEMPLATE, realText));
editor.setVisible(true);
} else { } else {
label.setText(""); editor.setText("");
label.setVisible(false); editor.setVisible(false);
} }
} }
@ -355,6 +362,12 @@ public class PickChoiceDialog extends MageDialog {
*/ */
public PickChoiceDialog() { public PickChoiceDialog() {
initComponents(); initComponents();
this.textMessage.enableHyperlinksAndCardPopups();
this.textMessage.enableTextLabelMode();
this.textSubMessage.enableHyperlinksAndCardPopups();
this.textSubMessage.enableTextLabelMode();
this.listChoices.setModel(dataModel); this.listChoices.setModel(dataModel);
this.setModal(true); this.setModal(true);
} }
@ -433,8 +446,8 @@ public class PickChoiceDialog extends MageDialog {
private void initComponents() { private void initComponents() {
panelHeader = new javax.swing.JPanel(); panelHeader = new javax.swing.JPanel();
labelMessage = new javax.swing.JLabel(); textMessage = new mage.client.components.MageEditorPane();
labelSubMessage = new javax.swing.JLabel(); textSubMessage = new mage.client.components.MageEditorPane();
panelSearch = new javax.swing.JPanel(); panelSearch = new javax.swing.JPanel();
labelSearch = new javax.swing.JLabel(); labelSearch = new javax.swing.JLabel();
editSearch = new javax.swing.JTextField(); editSearch = new javax.swing.JTextField();
@ -447,31 +460,23 @@ public class PickChoiceDialog extends MageDialog {
setResizable(true); setResizable(true);
labelMessage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); panelHeader.setLayout(new java.awt.BorderLayout());
labelMessage.setText("<html><div style='text-align: center;'>example long message example long message example long message example long message example long message</div></html>");
labelSubMessage.setFont(labelSubMessage.getFont().deriveFont((labelSubMessage.getFont().getStyle() | java.awt.Font.ITALIC) | java.awt.Font.BOLD)); textMessage.setEditable(false);
labelSubMessage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); textMessage.setBorder(null);
labelSubMessage.setText("<html><div style='text-align: center;'>example long message example long</div></html>"); textMessage.setText("<html><div style='text-align: center;'>example long message example long message example long message example long message example long message</div></html>");
textMessage.setAutoscrolls(false);
textMessage.setFocusable(false);
textMessage.setOpaque(false);
panelHeader.add(textMessage, java.awt.BorderLayout.CENTER);
javax.swing.GroupLayout panelHeaderLayout = new javax.swing.GroupLayout(panelHeader); textSubMessage.setEditable(false);
panelHeader.setLayout(panelHeaderLayout); textSubMessage.setBorder(null);
panelHeaderLayout.setHorizontalGroup( textSubMessage.setText("<html><div style='text-align: center;'>example long message example long</div></html>");
panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) textSubMessage.setAutoscrolls(false);
.addGroup(panelHeaderLayout.createSequentialGroup() textSubMessage.setFocusable(false);
.addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) textSubMessage.setOpaque(false);
.addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 337, Short.MAX_VALUE) panelHeader.add(textSubMessage, java.awt.BorderLayout.SOUTH);
.addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 337, Short.MAX_VALUE))
.addGap(0, 0, 0))
);
panelHeaderLayout.setVerticalGroup(
panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(panelHeaderLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(labelMessage)
.addGap(0, 0, 0)
.addComponent(labelSubMessage))
);
labelSearch.setText("Search:"); labelSearch.setText("Search:");
@ -558,7 +563,7 @@ public class PickChoiceDialog extends MageDialog {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, 371, Short.MAX_VALUE)
.addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap()) .addContainerGap())
); );
@ -570,7 +575,7 @@ public class PickChoiceDialog extends MageDialog {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 282, Short.MAX_VALUE) .addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 268, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap()) .addContainerGap())
@ -599,13 +604,13 @@ public class PickChoiceDialog extends MageDialog {
private javax.swing.JButton btOK; private javax.swing.JButton btOK;
private javax.swing.JCheckBox cbSpecial; private javax.swing.JCheckBox cbSpecial;
private javax.swing.JTextField editSearch; private javax.swing.JTextField editSearch;
private javax.swing.JLabel labelMessage;
private javax.swing.JLabel labelSearch; private javax.swing.JLabel labelSearch;
private javax.swing.JLabel labelSubMessage;
private javax.swing.JList listChoices; private javax.swing.JList listChoices;
private javax.swing.JPanel panelCommands; private javax.swing.JPanel panelCommands;
private javax.swing.JPanel panelHeader; private javax.swing.JPanel panelHeader;
private javax.swing.JPanel panelSearch; private javax.swing.JPanel panelSearch;
private javax.swing.JScrollPane scrollList; private javax.swing.JScrollPane scrollList;
private mage.client.components.MageEditorPane textMessage;
private mage.client.components.MageEditorPane textSubMessage;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }