From 17d2080e2790d1d2f9813a4ffae089b6b91dd9fa Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 11 Dec 2019 14:02:31 +0100 Subject: [PATCH 1/3] Added custom tab component --- src/dev/kske/chess/ui/GameTabComponent.java | 38 +++++++++++++++++++++ src/dev/kske/chess/ui/MainWindow.java | 15 ++++---- 2 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 src/dev/kske/chess/ui/GameTabComponent.java diff --git a/src/dev/kske/chess/ui/GameTabComponent.java b/src/dev/kske/chess/ui/GameTabComponent.java new file mode 100644 index 0000000..e436348 --- /dev/null +++ b/src/dev/kske/chess/ui/GameTabComponent.java @@ -0,0 +1,38 @@ +package dev.kske.chess.ui; + +import java.awt.FlowLayout; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; + +/** + * Project: Chess
+ * File: GameTabComponent.java
+ * Created: 11 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class GameTabComponent extends JPanel { + + private static final long serialVersionUID = 9022979950018125935L; + + public GameTabComponent(JTabbedPane tabbedPane) { + super(new FlowLayout(FlowLayout.LEFT, 0, 0)); + if (tabbedPane == null) throw new NullPointerException("TabbedPane is null"); + + // Create title JLabel + add(new JLabel() { + + private static final long serialVersionUID = 7902391411509551586L; + + @Override + public String getText() { + int i = tabbedPane.indexOfTabComponent(GameTabComponent.this); + return i != -1 ? tabbedPane.getTitleAt(i) : ""; + } + }); + + // TODO: Add closing button + } +} diff --git a/src/dev/kske/chess/ui/MainWindow.java b/src/dev/kske/chess/ui/MainWindow.java index 3dc54b5..22ccbc3 100644 --- a/src/dev/kske/chess/ui/MainWindow.java +++ b/src/dev/kske/chess/ui/MainWindow.java @@ -26,7 +26,7 @@ import dev.kske.chess.pgn.PGNGame; * Project: Chess
* File: MainWindow.java
* Created: 01.07.2019
- * + * * @since Chess v0.1-alpha * @author Kai S. K. Engelbart */ @@ -88,21 +88,22 @@ public class MainWindow extends JFrame { /** * Creates a new {@link GamePane}, adds it to the tabbed pane and opens it. * The new tab has the title {@code Game n} where {@code n} is its number. - * + * * @return The new {@link GamePane} */ - public GamePane addGamePane() { return addGamePane("Game " + (tabbedPane.getComponentCount() + 1)); } + public GamePane addGamePane() { return addGamePane("Game " + (tabbedPane.getTabCount() + 1)); } /** * Creates a new {@link GamePane}, adds it to the tabbed pane and opens it. - * + * * @param title The title of the {@link GamePane} * @return The new {@link GamePane} */ public GamePane addGamePane(String title) { GamePane gamePane = new GamePane(); tabbedPane.add(title, gamePane); - tabbedPane.setSelectedIndex(tabbedPane.getComponentCount() - 1); + tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new GameTabComponent(tabbedPane)); + tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1); return gamePane; } @@ -119,14 +120,14 @@ public class MainWindow extends JFrame { /** * Removes a {@link GamePane} form the tabbed pane. - * + * * @param index The index of the {@link GamePane} to remove */ public void removeGamePane(int index) { tabbedPane.remove(index); } /** * Loads a game file (FEN or PGN) and adds it to a new {@link GamePane}. - * + * * @param files the files to load the game from */ public void loadFiles(List files) { From cb79cc315992b736c9db777ab2f8a3ba0a7d7d24 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 11 Dec 2019 14:11:24 +0100 Subject: [PATCH 2/3] Added simple close button to tab component --- src/dev/kske/chess/ui/GameTabComponent.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/dev/kske/chess/ui/GameTabComponent.java b/src/dev/kske/chess/ui/GameTabComponent.java index e436348..c9b6bff 100644 --- a/src/dev/kske/chess/ui/GameTabComponent.java +++ b/src/dev/kske/chess/ui/GameTabComponent.java @@ -2,6 +2,7 @@ package dev.kske.chess.ui; import java.awt.FlowLayout; +import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTabbedPane; @@ -33,6 +34,11 @@ public class GameTabComponent extends JPanel { } }); - // TODO: Add closing button + JButton btnClose = new JButton("Close"); + btnClose.addActionListener((evt) -> { + int i = tabbedPane.indexOfTabComponent(GameTabComponent.this); + if (i != -1) tabbedPane.remove(i); + }); + add(btnClose); } } From 7008ad65aaf66aa2763fedc6ba524ce00332b20b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 11 Dec 2019 21:23:35 +0100 Subject: [PATCH 3/3] Improved close button UI --- src/dev/kske/chess/ui/GameTabComponent.java | 71 ++++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/src/dev/kske/chess/ui/GameTabComponent.java b/src/dev/kske/chess/ui/GameTabComponent.java index c9b6bff..ff492b4 100644 --- a/src/dev/kske/chess/ui/GameTabComponent.java +++ b/src/dev/kske/chess/ui/GameTabComponent.java @@ -1,11 +1,20 @@ package dev.kske.chess.ui; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTabbedPane; +import javax.swing.plaf.basic.BasicButtonUI; /** * Project: Chess
@@ -16,14 +25,17 @@ import javax.swing.JTabbedPane; */ public class GameTabComponent extends JPanel { + private final JTabbedPane tabbedPane; + private static final long serialVersionUID = 9022979950018125935L; public GameTabComponent(JTabbedPane tabbedPane) { super(new FlowLayout(FlowLayout.LEFT, 0, 0)); if (tabbedPane == null) throw new NullPointerException("TabbedPane is null"); + this.tabbedPane = tabbedPane; // Create title JLabel - add(new JLabel() { + JLabel label = new JLabel() { private static final long serialVersionUID = 7902391411509551586L; @@ -32,13 +44,56 @@ public class GameTabComponent extends JPanel { int i = tabbedPane.indexOfTabComponent(GameTabComponent.this); return i != -1 ? tabbedPane.getTitleAt(i) : ""; } - }); + }; + label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + add(label); - JButton btnClose = new JButton("Close"); - btnClose.addActionListener((evt) -> { - int i = tabbedPane.indexOfTabComponent(GameTabComponent.this); - if (i != -1) tabbedPane.remove(i); - }); - add(btnClose); + // Create close JButton + add(new TabButton()); + setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0)); + } + + private class TabButton extends JButton { + + private static final long serialVersionUID = -2757857832337636731L; + + public TabButton() { + final int size = 17; + setPreferredSize(new Dimension(size, size)); + setToolTipText("Close this tab"); + setUI(new BasicButtonUI()); + setContentAreaFilled(false); + setFocusable(false); + setBorder(BorderFactory.createEtchedBorder()); + setBorderPainted(false); + addMouseListener(new MouseAdapter() { + + @Override + public void mouseEntered(MouseEvent evt) { setBorderPainted(true); } + + @Override + public void mouseExited(MouseEvent evt) { setBorderPainted(false); } + }); + setRolloverEnabled(true); + addActionListener((evt) -> { int i = tabbedPane.indexOfTabComponent(GameTabComponent.this); if (i != -1) tabbedPane.remove(i); }); + } + + @Override + public void updateUI() {} + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g.create(); + // shift the image for pressed buttons + if (getModel().isPressed()) { g2.translate(1, 1); } + g2.setStroke(new BasicStroke(2)); + g2.setColor(Color.BLACK); + if (getModel().isRollover()) { g2.setColor(Color.MAGENTA); } + final int delta = 6; + g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1); + g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1); + g2.dispose(); + } } }