diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/QuestPanel.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/QuestPanel.java new file mode 100644 index 0000000..e334dcd --- /dev/null +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/QuestPanel.java @@ -0,0 +1,60 @@ +package thb.jeanluc.adventure.io; + +import thb.jeanluc.adventure.io.text.QuestText; +import thb.jeanluc.adventure.io.text.QuestView; +import thb.jeanluc.adventure.io.text.Span; +import thb.jeanluc.adventure.io.text.Style; + +import javax.swing.JTextPane; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledDocument; +import java.awt.Color; +import java.awt.Font; +import java.awt.Insets; + +/** Read-only styled view of the quest log, shown under the map. */ +public class QuestPanel extends JTextPane { + + public QuestPanel(Font font) { + setEditable(false); + setBackground(new Color(0x0b, 0x0e, 0x13)); + setForeground(new Color(0xcf, 0xd6, 0xe0)); + setFont(font.deriveFont(12f)); + setMargin(new Insets(8, 10, 8, 10)); + } + + public void show(QuestView view) { + SwingUtilities.invokeLater(() -> { + StyledDocument doc = getStyledDocument(); + try { + doc.remove(0, doc.getLength()); + for (Span sp : QuestText.render(view).spans()) { + SimpleAttributeSet as = new SimpleAttributeSet(); + StyleConstants.setForeground(as, colorFor(sp.style())); + if (sp.style() == Style.HEADING) { + StyleConstants.setBold(as, true); + } + doc.insertString(doc.getLength(), sp.text(), as); + } + setCaretPosition(0); + } catch (BadLocationException ignored) { + // replace-only; cannot occur with getLength() + } + }); + } + + private Color colorFor(Style s) { + return switch (s) { + case HEADING -> new Color(0xc9, 0x8a, 0xe0); + case ITEM -> new Color(0x46, 0xc8, 0xd8); + case NPC -> new Color(0xe6, 0xc3, 0x4a); + case EXIT -> new Color(0x6f, 0xcf, 0x73); + case DANGER -> new Color(0xe0, 0x6c, 0x6c); + case DIM -> new Color(0x6b, 0x72, 0x80); + case PLAIN -> new Color(0xcf, 0xd6, 0xe0); + }; + } +} diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/SwingIO.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/SwingIO.java index 86b9b53..fb4e4be 100644 --- a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/SwingIO.java +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/SwingIO.java @@ -2,6 +2,7 @@ package thb.jeanluc.adventure.io; import thb.jeanluc.adventure.io.text.Hud; import thb.jeanluc.adventure.io.text.MapView; +import thb.jeanluc.adventure.io.text.QuestView; import thb.jeanluc.adventure.io.text.RoomView; import thb.jeanluc.adventure.io.text.Span; import thb.jeanluc.adventure.io.text.Style; @@ -12,6 +13,7 @@ import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; +import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTextPane; @@ -70,6 +72,9 @@ public class SwingIO implements GameIO { private final JLabel hud; private final MapPanel map; private final JScrollPane sideScroll; + private final QuestPanel quests; + private final JScrollPane questScroll; + private final JPanel sidePanel; private final Font baseFont; /** Detected display scale (≥ 1.0); HiDPI panels report > 1.0 where supported. */ @@ -99,6 +104,14 @@ public class SwingIO implements GameIO { sideScroll = new JScrollPane(map); sideScroll.getViewport().setBackground(new Color(0x0e, 0x12, 0x18)); + quests = new QuestPanel(baseFont); + questScroll = new JScrollPane(quests); + questScroll.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, new Color(0x2a, 0x2f, 0x3a))); + + sidePanel = new JPanel(new BorderLayout()); + sidePanel.add(sideScroll, BorderLayout.CENTER); + sidePanel.add(questScroll, BorderLayout.SOUTH); + input = new JTextField(); input.addActionListener(e -> { String line = input.getText(); @@ -111,7 +124,7 @@ public class SwingIO implements GameIO { frame.setLayout(new BorderLayout()); frame.add(hud, BorderLayout.NORTH); frame.add(new JScrollPane(output), BorderLayout.CENTER); - frame.add(sideScroll, BorderLayout.EAST); + frame.add(sidePanel, BorderLayout.EAST); frame.add(input, BorderLayout.SOUTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize((int) (900 * uiScale), (int) (600 * uiScale)); @@ -171,8 +184,9 @@ public class SwingIO implements GameIO { int min = (int) (SIDE_MIN * uiScale); int max = (int) (SIDE_MAX * uiScale); int target = Math.max(min, Math.min(max, (int) (frame.getWidth() * SIDE_RATIO))); - sideScroll.setPreferredSize(new Dimension(target, 0)); - sideScroll.revalidate(); + sidePanel.setPreferredSize(new Dimension(target, 0)); + questScroll.setPreferredSize(new Dimension(target, (int) (frame.getHeight() * 0.32))); + sidePanel.revalidate(); frame.validate(); // The side panel changed size: let the map re-fit into it. map.revalidate(); @@ -197,6 +211,7 @@ public class SwingIO implements GameIO { output.setFont(baseFont.deriveFont(main)); input.setFont(baseFont.deriveFont(main)); hud.setFont(baseFont.deriveFont(small)); + quests.setFont(baseFont.deriveFont(small)); map.setZoom(zoom); frame.revalidate(); frame.repaint(); @@ -312,6 +327,16 @@ public class SwingIO implements GameIO { map.show(view); } + @Override + public void setQuests(QuestView view) { + quests.show(view); + } + + @Override + public void showQuests(QuestView view) { + // The GUI quest box is always visible; nothing extra to do. + } + @Override public void showMap(MapView view) { // The GUI map panel is always visible; nothing extra to do on the 'map' command.