diff --git a/CHANGELOG.md b/CHANGELOG.md
index 70f0e688..cbef6961 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@ FlatLaf Change Log
## Unreleased
- PasswordField: Warn about enabled Caps Lock.
+- TabbedPane: Support Ctrl+TAB / Ctrl+Shift+TAB to switch
+ to next / previous tab.
- TextField, FormattedTextField and PasswordField: Support round borders (see UI
default value `TextComponent.arc`). (issue #65)
- IntelliJ Themes: Added Gradianto themes to demo.
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatInputMaps.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatInputMaps.java
index 57c5822e..55450875 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatInputMaps.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatInputMaps.java
@@ -69,7 +69,14 @@ class FlatInputMaps
"ctrl PAGE_DOWN", "negativeBlockIncrement",
"ctrl PAGE_UP", "positiveBlockIncrement"
);
+ }
+ modifyInputMap( defaults, "TabbedPane.ancestorInputMap",
+ "ctrl TAB", "navigateNext",
+ "shift ctrl TAB", "navigatePrevious"
+ );
+
+ if( !SystemInfo.IS_MAC ) {
modifyInputMap( defaults, "Tree.focusInputMap",
"ADD", "expand",
"SUBTRACT", "collapse"
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java
index 5466dc0a..b4861f2b 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java
@@ -26,15 +26,21 @@ import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
+import java.awt.KeyboardFocusManager;
import java.awt.Rectangle;
import java.awt.Shape;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.util.Collections;
+import java.util.Set;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JTabbedPane;
+import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
@@ -90,6 +96,9 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatTabbedPaneUI
extends BasicTabbedPaneUI
{
+ private static Set focusForwardTraversalKeys;
+ private static Set focusBackwardTraversalKeys;
+
protected Color disabledForeground;
protected Color selectedBackground;
protected Color selectedForeground;
@@ -142,11 +151,27 @@ public class FlatTabbedPaneUI
tabHeight = scale( tabHeight );
tabSelectionHeight = scale( tabSelectionHeight );
+ // replace focus forward/backward traversal keys with TAB/Shift+TAB because
+ // the default also includes Ctrl+TAB/Ctrl+Shift+TAB, which we need to switch tabs
+ if( focusForwardTraversalKeys == null ) {
+ focusForwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, 0 ) );
+ focusBackwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, InputEvent.SHIFT_MASK ) );
+ }
+ // Ideally we should use `LookAndFeel.installProperty( tabPane, "focusTraversalKeysForward", keys )` here
+ // instead of `tabPane.setFocusTraversalKeys()`, but WindowsTabbedPaneUI also uses later method
+ // and switching from Windows LaF to FlatLaf would not replace the keys and Ctrl+TAB would not work.
+ tabPane.setFocusTraversalKeys( KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, focusForwardTraversalKeys );
+ tabPane.setFocusTraversalKeys( KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, focusBackwardTraversalKeys );
+
MigLayoutVisualPadding.install( tabPane, null );
}
@Override
protected void uninstallDefaults() {
+ // restore focus forward/backward traversal keys
+ tabPane.setFocusTraversalKeys( KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null );
+ tabPane.setFocusTraversalKeys( KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null );
+
super.uninstallDefaults();
disabledForeground = null;
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java
index 49d208cf..daf5779e 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java
@@ -81,7 +81,11 @@ public class FlatContainerTest
JSplitPane splitPane3 = new JSplitPane();
JSplitPane splitPane1 = new JSplitPane();
JPanel panel10 = new JPanel();
+ JTextField textField2 = new JTextField();
+ JButton button1 = new JButton();
JPanel panel11 = new JPanel();
+ JTextField textField3 = new JTextField();
+ JButton button2 = new JButton();
JSplitPane splitPane2 = new JSplitPane();
JPanel panel12 = new JPanel();
JPanel panel13 = new JPanel();
@@ -89,7 +93,11 @@ public class FlatContainerTest
tabbedPane1 = new JTabbedPane();
JPanel panel1 = new JPanel();
JLabel label1 = new JLabel();
+ JTextField textField4 = new JTextField();
+ JButton button3 = new JButton();
JPanel panel2 = new JPanel();
+ JTextField textField5 = new JTextField();
+ JButton button4 = new JButton();
JLabel label2 = new JLabel();
tabbedPane3 = new JTabbedPane();
JPanel panel5 = new JPanel();
@@ -145,6 +153,14 @@ public class FlatContainerTest
{
panel10.setBackground(Color.orange);
panel10.setLayout(new FlowLayout());
+
+ //---- textField2 ----
+ textField2.setText("some text");
+ panel10.add(textField2);
+
+ //---- button1 ----
+ button1.setText("...");
+ panel10.add(button1);
}
splitPane1.setLeftComponent(panel10);
@@ -152,6 +168,14 @@ public class FlatContainerTest
{
panel11.setBackground(Color.magenta);
panel11.setLayout(new FlowLayout());
+
+ //---- textField3 ----
+ textField3.setText("some text");
+ panel11.add(textField3);
+
+ //---- button2 ----
+ button2.setText("...");
+ panel11.add(button2);
}
splitPane1.setRightComponent(panel11);
}
@@ -195,6 +219,14 @@ public class FlatContainerTest
//---- label1 ----
label1.setText("TOP");
panel1.add(label1);
+
+ //---- textField4 ----
+ textField4.setText("some text");
+ panel1.add(textField4);
+
+ //---- button3 ----
+ button3.setText("...");
+ panel1.add(button3);
}
tabbedPane1.addTab("Tab 1", panel1);
@@ -202,6 +234,14 @@ public class FlatContainerTest
{
panel2.setBorder(new LineBorder(Color.magenta));
panel2.setLayout(new FlowLayout());
+
+ //---- textField5 ----
+ textField5.setText("some text");
+ panel2.add(textField5);
+
+ //---- button4 ----
+ button4.setText("...");
+ panel2.add(button4);
}
tabbedPane1.addTab("Tab 2", panel2);
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd
index d850940b..8fc771a9 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd
@@ -1,4 +1,4 @@
-JFDML JFormDesigner: "7.0.0.0.194" Java: "11.0.2" encoding: "UTF-8"
+JFDML JFormDesigner: "7.0.1.0.272" Java: "13.0.1" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -32,12 +32,28 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel10"
"background": sfield java.awt.Color orange
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField2"
+ "text": "some text"
+ } )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "button1"
+ "text": "..."
+ } )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "left"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel11"
"background": sfield java.awt.Color magenta
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField3"
+ "text": "some text"
+ } )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "button2"
+ "text": "..."
+ } )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "right"
} )
@@ -86,12 +102,28 @@ new FormModel {
name: "label1"
"text": "TOP"
} )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField4"
+ "text": "some text"
+ } )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "button3"
+ "text": "..."
+ } )
}, new FormLayoutConstraints( null ) {
"title": "Tab 1"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel2"
"border": &LineBorder0 new javax.swing.border.LineBorder( sfield java.awt.Color magenta, 1, false )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField5"
+ "text": "some text"
+ } )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "button4"
+ "text": "..."
+ } )
}, new FormLayoutConstraints( null ) {
"title": "Tab 2"
} )
diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_InputMap_1.8.0_202-mac.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_InputMap_1.8.0_202-mac.txt
index ff924a50..f680e51e 100644
--- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_InputMap_1.8.0_202-mac.txt
+++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_InputMap_1.8.0_202-mac.txt
@@ -536,11 +536,13 @@ SplitPane.ancestorInputMap [lazy] 14 javax.swing.plaf.InputMapUIResource
#---- TabbedPane ----
-TabbedPane.ancestorInputMap [lazy] 4 javax.swing.plaf.InputMapUIResource [UI]
+TabbedPane.ancestorInputMap [lazy] 6 javax.swing.plaf.InputMapUIResource [UI]
ctrl KP_UP requestFocus
ctrl PAGE_DOWN navigatePageDown
ctrl PAGE_UP navigatePageUp
+ ctrl TAB navigateNext
ctrl UP requestFocus
+ shift ctrl TAB navigatePrevious
TabbedPane.focusInputMap [lazy] 10 javax.swing.plaf.InputMapUIResource [UI]
ctrl DOWN requestFocusForVisibleComponent
ctrl KP_DOWN requestFocusForVisibleComponent
diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_InputMap_1.8.0_202.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_InputMap_1.8.0_202.txt
index dd37c8ab..16db08bf 100644
--- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_InputMap_1.8.0_202.txt
+++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_InputMap_1.8.0_202.txt
@@ -475,11 +475,13 @@ SplitPane.ancestorInputMap [lazy] 14 javax.swing.plaf.InputMapUIResource
#---- TabbedPane ----
-TabbedPane.ancestorInputMap [lazy] 4 javax.swing.plaf.InputMapUIResource [UI]
+TabbedPane.ancestorInputMap [lazy] 6 javax.swing.plaf.InputMapUIResource [UI]
ctrl KP_UP requestFocus
ctrl PAGE_DOWN navigatePageDown
ctrl PAGE_UP navigatePageUp
+ ctrl TAB navigateNext
ctrl UP requestFocus
+ shift ctrl TAB navigatePrevious
TabbedPane.focusInputMap [lazy] 10 javax.swing.plaf.InputMapUIResource [UI]
ctrl DOWN requestFocusForVisibleComponent
ctrl KP_DOWN requestFocusForVisibleComponent