Browse Source

TabFrame: Add method to add custom buttons to the popup header

Managing the style of the header for buttons is non-trivial, so
we have the UI expose an api to create matching styled button for
the user.
pull/307/head
Jannis Weis 3 years ago
parent
commit
e722048341
No known key found for this signature in database
GPG Key ID: 7C9D8D4B558049AB
  1. 62
      core/src/main/java/com/github/weisj/darklaf/components/tabframe/JTabFrame.java
  2. 12
      core/src/main/java/com/github/weisj/darklaf/components/tabframe/PanelPopup.java
  3. 19
      core/src/main/java/com/github/weisj/darklaf/components/tabframe/TabFramePopup.java
  4. 20
      core/src/main/java/com/github/weisj/darklaf/components/tabframe/TabFramePopupUI.java
  5. 33
      core/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkPanelPopupUI.java
  6. 5
      core/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkTabbedPopupUI.java
  7. 14
      core/src/test/java/com/github/weisj/darklaf/ui/tabFrame/TabFrameDemo.java

62
core/src/main/java/com/github/weisj/darklaf/components/tabframe/JTabFrame.java

@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2019-2021 Jannis Weis * Copyright (c) 2019-2022 Jannis Weis
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, * associated documentation files (the "Software"), to deal in the Software without restriction,
@ -487,7 +487,7 @@ public class JTabFrame extends JComponent {
* Get the component at the given position. * Get the component at the given position.
* *
* @param a the alignment position.{@link TabFramePosition#getAlignment()} * @param a the alignment position.{@link TabFramePosition#getAlignment()}
* @param index the index. {@link TabFramePosition#getIndex()} ()} * @param index the index. {@link TabFramePosition#getIndex()}
* @return the popup component specified by {@link TabFramePopup#getContentPane()}. * @return the popup component specified by {@link TabFramePopup#getContentPane()}.
* @throws IndexOutOfBoundsException if the alignment or index is out of bounds, or the tab doesn't * @throws IndexOutOfBoundsException if the alignment or index is out of bounds, or the tab doesn't
* exist. * exist.
@ -626,6 +626,17 @@ public class JTabFrame extends JComponent {
doLayout(); doLayout();
} }
/**
* Get the popup at the given position that is currently active.
*
* @param a the alignment position. {@link TabFramePosition#getAlignment()}
* @return the popup specified by {@link TabFramePopup#getComponent()}.
*/
public TabFramePopup getPopupAt(final Alignment a) {
List<TabFramePopup> tabs = compsForAlignment(a);
return tabs.get(Math.max(Math.min(tabs.size() - 1, selectedIndices[a.ordinal()]), 0));
}
/** /**
* Get the popup component at the given position that is currently active. * Get the popup component at the given position that is currently active.
* *
@ -633,8 +644,30 @@ public class JTabFrame extends JComponent {
* @return the popup component specified by {@link TabFramePopup#getComponent()}. * @return the popup component specified by {@link TabFramePopup#getComponent()}.
*/ */
public Component getPopupComponentAt(final Alignment a) { public Component getPopupComponentAt(final Alignment a) {
return getPopupAt(a).getComponent();
}
/**
* Get the popup at the given position.
*
* @param a the alignment position.{@link TabFramePosition#getAlignment()}
* @param index the index.{@link TabFramePosition#getIndex()}
* @return the popup specified by {@link TabFramePopup#getComponent()}.
*/
public TabFramePopup getPopupAt(final Alignment a, final int index) {
List<TabFramePopup> tabs = compsForAlignment(a); List<TabFramePopup> tabs = compsForAlignment(a);
return tabs.get(Math.max(Math.min(tabs.size() - 1, selectedIndices[a.ordinal()]), 0)).getComponent(); return tabs.get(index);
}
/**
* Get the popup component at the given position.
*
* @param a the alignment position.{@link TabFramePosition#getAlignment()}
* @param index the index.{@link TabFramePosition#getIndex()}
* @return the popup component specified by {@link TabFramePopup#getComponent()}.
*/
public Component getPopupComponentAt(final Alignment a, final int index) {
return getPopupAt(a, index).getComponent();
} }
/** /**
@ -785,29 +818,6 @@ public class JTabFrame extends JComponent {
getTabContainer(a).remove(tab.getComponent()); getTabContainer(a).remove(tab.getComponent());
} }
/**
* Get the popup component at the given position.
*
* @param a the alignment position.{@link TabFramePosition#getAlignment()}
* @param index the index.{@link TabFramePosition#getIndex()}
* @return the popup component specified by {@link TabFramePopup#getComponent()}.
*/
public Component getPopupComponentAt(final Alignment a, final int index) {
List<TabFramePopup> tabs = compsForAlignment(a);
return tabs.get(index).getComponent();
}
/**
* Get the component at the given position.
*
* @param a the alignment position. {@link TabFramePosition#getAlignment()}
* @return the component specified by {@link TabFramePopup#getContentPane()}.
*/
public Component getComponentAt(final Alignment a) {
List<TabFramePopup> tabs = compsForAlignment(a);
return tabs.get(Math.max(Math.min(tabs.size() - 1, selectedIndices[a.ordinal()]), 0)).getContentPane();
}
/** /**
* Get the custom tab component at the given position. * Get the custom tab component at the given position.
* *

12
core/src/main/java/com/github/weisj/darklaf/components/tabframe/PanelPopup.java

@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2019-2021 Jannis Weis * Copyright (c) 2019-2022 Jannis Weis
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, * associated documentation files (the "Software"), to deal in the Software without restriction,
@ -145,6 +145,16 @@ public class PanelPopup extends JPanel implements TabFramePopup {
} }
} }
@Override
public AbstractButton addButton(final Icon icon, final String tooltipText) {
return getPopupUI().addButton(icon, tooltipText);
}
@Override
public void removeButton(AbstractButton button) {
getPopupUI().removeButton(button);
}
@Override @Override
public void setOpen(final boolean open) { public void setOpen(final boolean open) {
boolean old = this.open; boolean old = this.open;

19
core/src/main/java/com/github/weisj/darklaf/components/tabframe/TabFramePopup.java

@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2019-2021 Jannis Weis * Copyright (c) 2019-2022 Jannis Weis
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, * associated documentation files (the "Software"), to deal in the Software without restriction,
@ -71,6 +71,23 @@ public interface TabFramePopup {
} }
} }
/**
* Add a button to the popup matching the frames' appearance.
*
* @param icon the icon of the button
* @param tooltipText the tooltip text
* @return the added button. Use this to configure any actions.
*/
AbstractButton addButton(final Icon icon, final String tooltipText);
/**
* Remove a button added through {@link #addButton(Icon, String)}.
*
* @param button the button to remove
*/
void removeButton(final AbstractButton button);
/** /**
* Get the {{@link JTabFrame}} this popup belongs to. * Get the {{@link JTabFrame}} this popup belongs to.
* *

20
core/src/main/java/com/github/weisj/darklaf/components/tabframe/TabFramePopupUI.java

@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2019-2021 Jannis Weis * Copyright (c) 2019-2022 Jannis Weis
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, * associated documentation files (the "Software"), to deal in the Software without restriction,
@ -20,5 +20,23 @@
*/ */
package com.github.weisj.darklaf.components.tabframe; package com.github.weisj.darklaf.components.tabframe;
import javax.swing.*;
public interface TabFramePopupUI { public interface TabFramePopupUI {
/**
* Add a button to the popup matching the frames' appearance.
*
* @param icon the icon of the button
* @param tooltipText the tooltip text
* @return the added button. Use this to configure any actions.
*/
AbstractButton addButton(final Icon icon, final String tooltipText);
/**
* Remove a button added through {@link #addButton(Icon, String)}.
*
* @param button the button to remove
*/
void removeButton(final AbstractButton button);
} }

33
core/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkPanelPopupUI.java

@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2019-2021 Jannis Weis * Copyright (c) 2019-2022 Jannis Weis
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, * associated documentation files (the "Software"), to deal in the Software without restriction,
@ -34,6 +34,7 @@ import com.github.weisj.darklaf.components.tabframe.PanelPopup;
import com.github.weisj.darklaf.components.tabframe.TabFramePopup; import com.github.weisj.darklaf.components.tabframe.TabFramePopup;
import com.github.weisj.darklaf.components.tabframe.TabFramePopupUI; import com.github.weisj.darklaf.components.tabframe.TabFramePopupUI;
import com.github.weisj.darklaf.components.uiresource.JLabelUIResource; import com.github.weisj.darklaf.components.uiresource.JLabelUIResource;
import com.github.weisj.darklaf.components.uiresource.JPanelUIResource;
import com.github.weisj.darklaf.focus.FocusParentHelper; import com.github.weisj.darklaf.focus.FocusParentHelper;
import com.github.weisj.darklaf.ui.button.DarkButtonUI; import com.github.weisj.darklaf.ui.button.DarkButtonUI;
import com.github.weisj.darklaf.ui.panel.DarkPanelUI; import com.github.weisj.darklaf.ui.panel.DarkPanelUI;
@ -48,6 +49,7 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
private final Action closeAction = Actions.create(e -> closeButton.doClick()); private final Action closeAction = Actions.create(e -> closeButton.doClick());
protected JPanel content; protected JPanel content;
protected JLabel label; protected JLabel label;
protected JComponent customButtonArea;
protected Color headerFocusBackground; protected Color headerFocusBackground;
protected Color headerButtonFocusHoverBackground; protected Color headerButtonFocusHoverBackground;
protected Color headerButtonFocusClickBackground; protected Color headerButtonFocusClickBackground;
@ -91,6 +93,7 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
protected void installComponents() { protected void installComponents() {
closeButton = createCloseButton(); closeButton = createCloseButton();
label = createLabel(); label = createLabel();
customButtonArea = createCustomButtonArea();
header = createHeader(); header = createHeader();
JPanel headerContainer = new JPanel(new BorderLayout()); JPanel headerContainer = new JPanel(new BorderLayout());
@ -111,6 +114,14 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
content.setBorder(contentBorder); content.setBorder(contentBorder);
} }
protected JComponent createCustomButtonArea() {
JPanelUIResource buttonHolder = new JPanelUIResource();
buttonHolder.setLayout(new BoxLayout(buttonHolder, BoxLayout.X_AXIS));
buttonHolder.setOpaque(false);
buttonHolder.setBorder(BorderFactory.createEmptyBorder());
return buttonHolder;
}
protected void installListeners() { protected void installListeners() {
popupComponent.addPropertyChangeListener(this); popupComponent.addPropertyChangeListener(this);
installFocusListener(); installFocusListener();
@ -131,6 +142,19 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
}); });
} }
@Override
public AbstractButton addButton(final Icon icon, String tooltipText) {
HeaderButton button = new HeaderButton(icon, this);
button.setToolTipText(tooltipText);
customButtonArea.add(button);
return button;
}
@Override
public void removeButton(final AbstractButton button) {
customButtonArea.remove(button);
}
protected HeaderButton createCloseButton() { protected HeaderButton createCloseButton() {
HeaderButton closeButton = new HeaderButton(UIManager.getIcon("TabFramePopup.close.icon"), this); HeaderButton closeButton = new HeaderButton(UIManager.getIcon("TabFramePopup.close.icon"), this);
closeButton.addActionListener(e -> popupComponent.close()); closeButton.addActionListener(e -> popupComponent.close());
@ -152,6 +176,7 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
header.add(Box.createHorizontalStrut(5)); header.add(Box.createHorizontalStrut(5));
header.add(label); header.add(label);
header.add(Box.createGlue()); header.add(Box.createGlue());
header.add(customButtonArea);
header.add(closeButton); header.add(closeButton);
header.add(Box.createHorizontalStrut(1)); header.add(Box.createHorizontalStrut(1));
header.setBorder(UIManager.getBorder("TabFramePopup.headerBorder")); header.setBorder(UIManager.getBorder("TabFramePopup.headerBorder"));
@ -163,6 +188,9 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
if (header != null) { if (header != null) {
header.setBackground(focus ? headerFocusBackground : headerBackground); header.setBackground(focus ? headerFocusBackground : headerBackground);
} }
for (Component customButton : customButtonArea.getComponents()) {
if (customButton instanceof HeaderButton) ((HeaderButton) customButton).setFocus(focus);
}
if (oldFocus != focus) { if (oldFocus != focus) {
if (header != null) { if (header != null) {
header.repaint(); header.repaint();
@ -372,6 +400,9 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
setFocus(false); setFocus(false);
setFocusable(false); setFocusable(false);
setOpaque(false); setOpaque(false);
System.out.println(icon.getIconWidth() + " " + icon.getIconHeight());
System.out.println(getPreferredSize());
} }
public void setFocus(final boolean focus) { public void setFocus(final boolean focus) {

5
core/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkTabbedPopupUI.java

@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2019-2021 Jannis Weis * Copyright (c) 2019-2022 Jannis Weis
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, * associated documentation files (the "Software"), to deal in the Software without restriction,
@ -76,6 +76,7 @@ public class DarkTabbedPopupUI extends DarkPanelPopupUI implements TabFrameTabbe
protected void installComponents() { protected void installComponents() {
closeButton = createCloseButton(); closeButton = createCloseButton();
label = createLabel(); label = createLabel();
customButtonArea = createCustomButtonArea();
tabbedPane = getTabbedPane(); tabbedPane = getTabbedPane();
setupTabbedPane(); setupTabbedPane();
border = createBorder(); border = createBorder();
@ -107,11 +108,11 @@ public class DarkTabbedPopupUI extends DarkPanelPopupUI implements TabFrameTabbe
JPanelUIResource buttonHolder = new JPanelUIResource(); JPanelUIResource buttonHolder = new JPanelUIResource();
buttonHolder.setLayout(new BoxLayout(buttonHolder, BoxLayout.X_AXIS)); buttonHolder.setLayout(new BoxLayout(buttonHolder, BoxLayout.X_AXIS));
buttonHolder.add(Box.createHorizontalStrut(1)); buttonHolder.add(Box.createHorizontalStrut(1));
buttonHolder.add(customButtonArea);
buttonHolder.add(closeButton); buttonHolder.add(closeButton);
buttonHolder.add(Box.createHorizontalStrut(1)); buttonHolder.add(Box.createHorizontalStrut(1));
buttonHolder.setBorder(UIManager.getBorder("TabFramePopup.headerBorder")); buttonHolder.setBorder(UIManager.getBorder("TabFramePopup.headerBorder"));
buttonHolder.setOpaque(false); buttonHolder.setOpaque(false);
tabbedPane.setOpaque(false); tabbedPane.setOpaque(false);
tabbedPane.putClientProperty("JTabbedPane.leadingComponent", label); tabbedPane.putClientProperty("JTabbedPane.leadingComponent", label);
tabbedPane.putClientProperty("JTabbedPane.trailingComponent", buttonHolder); tabbedPane.putClientProperty("JTabbedPane.trailingComponent", buttonHolder);

14
core/src/test/java/com/github/weisj/darklaf/ui/tabFrame/TabFrameDemo.java

@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2019-2021 Jannis Weis * Copyright (c) 2019-2022 Jannis Weis
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, * associated documentation files (the "Software"), to deal in the Software without restriction,
@ -49,7 +49,6 @@ public class TabFrameDemo extends BaseComponentDemo {
DemoExecutor.showDemo(new TabFrameDemo()); DemoExecutor.showDemo(new TabFrameDemo());
} }
@Override @Override
public Dimension getWindowSize() { public Dimension getWindowSize() {
return new Dimension(1000, 500); return new Dimension(1000, 500);
@ -100,6 +99,17 @@ public class TabFrameDemo extends BaseComponentDemo {
panel.add(label); panel.add(label);
tabbedPopup.getTabbedPane().addTab("Tab " + i, panel); tabbedPopup.getTabbedPane().addTab("Tab " + i, panel);
} }
for (int i = 0; i < 3; i++) {
String text = "Custom Button " + i;
tabbedPopup
.addButton(AllIcons.Menu.Help.get(), text)
.addActionListener(e -> JOptionPane.showMessageDialog(tabFrame, text));
tabFrame.getPopupAt(Alignment.EAST, 0)
.addButton(AllIcons.Menu.Help.get(), "Custom Button")
.addActionListener(e -> JOptionPane.showMessageDialog(tabFrame, text));
}
/* /*
* Activate for a custom tab. tabFrame.setUserTabComponentAt(new JLabel("NORTH (custom tab)") {{ * Activate for a custom tab. tabFrame.setUserTabComponentAt(new JLabel("NORTH (custom tab)") {{
* setBorder(new EmptyBorder(0, 5, 0, 5)); setOpaque(false); setForeground(Color.RED); setFont(new * setBorder(new EmptyBorder(0, 5, 0, 5)); setOpaque(false); setForeground(Color.RED); setFont(new

Loading…
Cancel
Save