Textured Tool Bar Sample Code
This sample program simulates the appearance of the tool bars in the Mail and TextEdit applications.
import java.awt.*; import java.awt.geom.RoundRectangle2D; import javax.swing.*; import org.jetbrains.annotations.*; /** * Sample program for textured tool bars. The application specific icons are not included! */ public class ToolbarSampleProgram { public final static int POSITION_FIRST = 0; public final static int POSITION_MIDDLE = 1; public final static int POSITION_LAST = 2; public final static int POSITION_ONLY = 3; protected final Icon defaultIcon = createDefaultIcon(); public ToolbarSampleProgram() { { MailFrame fr = new MailFrame(); fr.setBounds(50, 100, 800, 600); fr.setVisible(true); } { TextEditFrame fr = new TextEditFrame(); fr.setBounds(900, 200, 600, 600); fr.setVisible(true); } } protected class SampleToolbarFrame extends JFrame { public SampleToolbarFrame(@NotNull JToolBar toolBar) { JRootPane rootPane = getRootPane(); rootPane.putClientProperty("Aqua.windowStyle", "unifiedToolBar"); setLayout(new BorderLayout()); add(toolBar, BorderLayout.NORTH); } } protected class MailFrame extends SampleToolbarFrame { private final JPanel p; public MailFrame() { super(new MailToolbar("regular")); p = new JPanel(); p.setFocusable(true); add(p); } @Override public void addNotify() { super.addNotify(); p.requestFocusInWindow(); } } protected class TextEditFrame extends SampleToolbarFrame { private final JTextPane p; public TextEditFrame() { super(new TextEditToolbar("mini")); p = new JTextPane(); add(p); } @Override public void addNotify() { super.addNotify(); p.requestFocusInWindow(); } } protected class MailToolbar extends JToolBar { public MailToolbar(@NotNull String sizeVariant) { add(new MyMailRow(sizeVariant)); } } protected class TextEditToolbar extends JToolBar { public TextEditToolbar(@NotNull String sizeVariant) { add(new MyTextEditRow(sizeVariant)); } } protected class RowPaneBase extends JPanel { protected GroupLayout.SequentialGroup hGroup; protected GroupLayout.ParallelGroup vGroup; protected RowPaneBase() { setOpaque(false); GroupLayout layout = new GroupLayout(this); setLayout(layout); hGroup = layout.createSequentialGroup(); vGroup = layout.createParallelGroup(); layout.setHorizontalGroup(hGroup); layout.setVerticalGroup(vGroup); } protected void add(@NotNull JComponent c) { hGroup.addComponent(c, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); vGroup.addComponent(c); } protected void add(@NotNull JComponent c, int width) { hGroup.addComponent(c, width, width, width); vGroup.addComponent(c); } protected void addExpandingGap() { hGroup.addGap(0, 10, 10000); vGroup.addGap(0); } protected void addGap(int width) { hGroup.addGap(width, width, width); vGroup.addGap(0); } } protected abstract class RowBase extends RowPaneBase { protected final @NotNull String sizeVariant; private final int buttonWidth = 41; private final int iconSize; private final float sizeFudge; protected RowBase(@NotNull String sizeVariant) { this.sizeVariant = sizeVariant; iconSize = determineIconSize(); sizeFudge = determineSizeFudge(); } protected int determineIconSize() { if (sizeVariant.equals("small")) { return 13; } else if (sizeVariant.equals("mini")) { return 11; } else { return 15; } } protected float determineSizeFudge() { // assumes sizes are based on "regular" if (sizeVariant.equals("small")) { return 0.85f; } else if (sizeVariant.equals("mini")) { return 0.75f; } else { return 1; } } @Override protected void add(@NotNull JComponent c, int width) { width = (int) (width * sizeFudge); c.setMinimumSize(new Dimension(width, 0)); c.setMaximumSize(new Dimension(width, 1000)); super.add(c, width); } protected AbstractButton createPushButton(@NotNull Icon icon) { return createSegmentedButton(icon, POSITION_ONLY); } protected AbstractButton createPushButton(@NotNull String label) { return createSegmentedButton(label, POSITION_ONLY); } protected AbstractButton createToggleButton(@NotNull Icon icon) { return createSegmentedToggleButton(icon, POSITION_ONLY); } protected AbstractButton createToggleButton(@NotNull String label) { return createSegmentedToggleButton(label, POSITION_ONLY); } protected AbstractButton createSegmentedButton(@NotNull Icon icon, int position) { JButton b = new JButton(icon); b.putClientProperty("JButton.buttonType", "segmented"); b.putClientProperty("JButton.segmentPosition", toPosition(position)); return setup(b); } protected AbstractButton createSegmentedButton(@NotNull String label, int position) { JButton b = new JButton(label); b.putClientProperty("JButton.buttonType", "segmented"); b.putClientProperty("JButton.segmentPosition", toPosition(position)); return setup(b); } protected AbstractButton createSegmentedToggleButton(@NotNull Icon icon, int position) { JToggleButton b = new JToggleButton(icon); b.putClientProperty("JButton.buttonType", "segmented"); b.putClientProperty("JButton.segmentPosition", toPosition(position)); return setup(b); } protected AbstractButton createSegmentedToggleButton(@NotNull String label, int position) { JToggleButton b = new JToggleButton(label); b.putClientProperty("JButton.buttonType", "segmented"); b.putClientProperty("JButton.segmentPosition", toPosition(position)); return setup(b); } protected AbstractButton createSegmentedColorButton(@NotNull String label, int position, @Nullable Color color) { JButton b = new ColorButton(label, color); b.putClientProperty("JButton.buttonType", "segmented"); b.putClientProperty("JButton.segmentPosition", toPosition(position)); return setup(b); } protected AbstractButton createSeparatedButton(@NotNull Icon icon, int position) { JButton b = new JButton(icon); b.putClientProperty("JButton.buttonType", "segmentedSeparated"); b.putClientProperty("JButton.segmentPosition", toPosition(position)); return setup(b); } protected JComboBox createPullDownButton(@NotNull String label) { JComboBox b = new JComboBox(); b.setEditable(false); b.putClientProperty("JComponent.sizeVariant", sizeVariant); b.putClientProperty("JComboBox.isPopDown", true); b.putClientProperty("JComboBox.title", label); return b; } protected JComboBox createPullDownButton(@NotNull Icon icon) { JComboBox b = new JComboBox(); b.setEditable(false); b.putClientProperty("JComponent.sizeVariant", sizeVariant); b.putClientProperty("JComboBox.isPopDown", true); b.putClientProperty("JComboBox.title", icon); return b; } protected JComboBox createPopUpButton() { JComboBox b = new JComboBox(); b.setEditable(false); b.putClientProperty("JComponent.sizeVariant", sizeVariant); return b; } protected JComboBox createComboBox() { JComboBox b = new JComboBox(); b.setEditable(true); b.putClientProperty("JComponent.sizeVariant", sizeVariant); return b; } protected JTextField createTextField() { JTextField t = new JTextField(); t.putClientProperty("JComponent.sizeVariant", sizeVariant); return t; } protected JTextField createSearchField() { JTextField t = new JTextField(); t.putClientProperty("JComponent.sizeVariant", sizeVariant); t.putClientProperty("JTextField.style", "search"); return t; } protected AbstractButton setup(@NotNull AbstractButton b) { b.putClientProperty("JComponent.sizeVariant", sizeVariant); if (!b.isMinimumSizeSet()) { b.setMinimumSize(new Dimension(buttonWidth, 0)); } return b; } protected @NotNull Icon getIcon(@NotNull String name) { return adjustIcon(defaultIcon); } protected @NotNull Icon adjustIcon(@NotNull Icon ic) { if (ic instanceof ImageIcon) { ImageIcon ii = (ImageIcon) ic; double sx = (1.3 * iconSize * sizeFudge) / ic.getIconWidth(); double sy = (1.0 * iconSize * sizeFudge) / ic.getIconHeight(); double s = Math.min(sx, sy); int width = (int) (ic.getIconWidth() * s); int height = (int) (ic.getIconHeight() * s); return new ImageIcon(ii.getImage().getScaledInstance(width, height, 0)); } else { return ic; } } } /** A row of components that simulates the contents of the Mail toolbar. Mail uses regular size. */ protected class MyMailRow extends RowBase { private AbstractButton getMailButton; private AbstractButton composeButton; private AbstractButton archiveButton; private AbstractButton trashButton; private AbstractButton junkButton; private AbstractButton replyButton; private AbstractButton replyAllButton; private AbstractButton forwardButton; private AbstractButton flagButton; private AbstractButton flagMenuButton; private JTextField searchField; public MyMailRow(@NotNull String sizeVariant) { super(sizeVariant); getMailButton = createPushButton(getIcon("GetMailTemplate")); composeButton = createPushButton(getIcon("ComposeTemplate")); archiveButton = createPushButton(getIcon("ArchiveTemplate")); trashButton = createSegmentedButton(getIcon("TrashTemplate"), POSITION_FIRST); junkButton = createSegmentedButton(getIcon("JunkTemplate"), POSITION_LAST); replyButton = createSegmentedButton(getIcon("ReplyTemplate"), POSITION_FIRST); replyAllButton = createSegmentedButton(getIcon("ReplyAllTemplate"), POSITION_MIDDLE); forwardButton = createSegmentedButton(getIcon("ForwardTemplate"), POSITION_LAST); flagButton = createSegmentedButton(getIcon("Flag"), POSITION_FIRST); flagMenuButton = createSegmentedButton(getIcon("DownMenuTemplate"), POSITION_LAST); searchField = createSearchField(); addGap(8); add(getMailButton, 38); addGap(8); add(composeButton, 38); addGap(82); add(archiveButton, 38); addGap(8); add(trashButton, 36); add(junkButton, 36); addGap(8); add(replyButton, 36); add(replyAllButton, 35); add(forwardButton, 36); addGap(8); add(flagButton, 27); add(flagMenuButton, 15); addExpandingGap(); add(searchField, 325); addGap(8); } } /** A row of components that simulates the contents of the TextEdit toolbar. TextEdit uses mini size. */ protected class MyTextEditRow extends RowBase { private JComboBox paragraphStyleMenuButton; private JComboBox fontFamilyMenuButton; private JComboBox typefaceMenuButton; private JComboBox fontSizeSelector; private AbstractButton textColorButton; private AbstractButton textBackgroundColorButton; private AbstractButton boldButton; private AbstractButton italicButton; private AbstractButton underlineButton; private AbstractButton leftAlignButton; private AbstractButton centerAlignButton; private AbstractButton rightAlignButton; private AbstractButton justifyButton; private JComboBox spacingMenuButton; private JComboBox listFormatMenuButton; public MyTextEditRow(@NotNull String sizeVariant) { super(sizeVariant); paragraphStyleMenuButton = createPullDownButton("\u00B6"); fontFamilyMenuButton = createPopUpButton(); typefaceMenuButton = createPopUpButton(); fontSizeSelector = createComboBox(); textColorButton = createSegmentedColorButton("", POSITION_ONLY, Color.BLACK); textBackgroundColorButton = createSegmentedColorButton("a", POSITION_ONLY, null); boldButton = createSegmentedToggleButton("B", POSITION_FIRST); italicButton = createSegmentedToggleButton("I", POSITION_MIDDLE); underlineButton = createSegmentedToggleButton("U", POSITION_LAST); leftAlignButton = createSegmentedToggleButton(getIcon("LeftAlignTemplate"), POSITION_FIRST); centerAlignButton = createSegmentedToggleButton(getIcon("CenterTemplate"), POSITION_MIDDLE); rightAlignButton = createSegmentedToggleButton(getIcon("RightAlignTemplate"), POSITION_MIDDLE); justifyButton = createSegmentedToggleButton(getIcon("JustifyTemplate"), POSITION_LAST); spacingMenuButton = createPopUpButton(); listFormatMenuButton = createPullDownButton(getIcon("ListFormatTemplate")); paragraphStyleMenuButton.setModel(createParagraphStyleModel()); fontFamilyMenuButton.setModel(createFontFamilyModel()); typefaceMenuButton.setModel(createTypeFaceModel()); fontSizeSelector.setModel(createFontSizeModel()); spacingMenuButton.setModel(createSpacingModel()); listFormatMenuButton.setModel(createListFormatModel()); boldButton.setSelected(true); { Font f = textBackgroundColorButton.getFont(); textBackgroundColorButton.setFont(f.deriveFont(f.getSize2D()+4).deriveFont(Font.BOLD)); } { int size = getTypeSize(); boldButton.setFont(new Font("Baskerville", Font.BOLD, size)); italicButton.setFont(new Font("Baskerville", Font.BOLD + Font.ITALIC, size)); underlineButton.setFont(new Font("Baskerville", Font.PLAIN, size)); } { Color g = new Color(115, 115, 115); boldButton.setForeground(g); italicButton.setForeground(g); underlineButton.setForeground(g); italicButton.setEnabled(false); } { ButtonGroup g = new ButtonGroup(); g.add(leftAlignButton); g.add(centerAlignButton); g.add(rightAlignButton); g.add(justifyButton); leftAlignButton.setSelected(true); } add(paragraphStyleMenuButton, 26); addGap(6); add(fontFamilyMenuButton, 99); addGap(2); add(typefaceMenuButton, 79); addGap(2); add(fontSizeSelector, 45); addGap(6); add(textColorButton, 23); addGap(2); add(textBackgroundColorButton, 23); addGap(6); add(boldButton, 18); add(italicButton, 18); add(underlineButton, 18); addGap(6); add(leftAlignButton, 18); add(centerAlignButton, 18); add(rightAlignButton, 18); add(justifyButton, 18); addGap(6); add(spacingMenuButton, 38); addGap(2); add(listFormatMenuButton, 38); } protected int getTypeSize() { if (sizeVariant.equals("small")) { return 15; } else if (sizeVariant.equals("regular")) { return 18; } else { return 13; } } @Override protected float determineSizeFudge() { // sizes are based on "mini" if (sizeVariant.equals("small")) { return 1.15f; } else if (sizeVariant.equals("regular")) { return 1.35f; } else { return 1; } } } private ComboBoxModel createParagraphStyleModel() { String[] items = { "Default", "Header" }; return new DefaultComboBoxModel<>(items); } private ComboBoxModel createFontFamilyModel() { String[] items = { "Lucida Grande", "Helvetica" }; return new DefaultComboBoxModel<>(items); } private ComboBoxModel createTypeFaceModel() { String[] items = { "Regular", "Bold" }; return new DefaultComboBoxModel<>(items); } private ComboBoxModel createFontSizeModel() { String[] items = { "9", "10", "11", "12", "13", "14", "18", "24", "36", "48", "64" }; return new DefaultComboBoxModel<>(items); } private ComboBoxModel createSpacingModel() { String[] items = { "0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5" }; ComboBoxModel model = new DefaultComboBoxModel<>(items); model.setSelectedItem("1.0"); return model; } private ComboBoxModel createListFormatModel() { String[] items = { "None", "1. 2. 3..." }; return new DefaultComboBoxModel<>(items); } private class ColorButton extends JButton { private @Nullable Color color; public ColorButton(@NotNull String label, @Nullable Color color) { super(label); this.color = color; } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D gg = (Graphics2D) g; gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int x = 3; int y = 3; int right = getWidth() - 6; int bottom = getHeight() - 8; Shape s = new RoundRectangle2D.Double(x, y, right, bottom, 4, 4); if (color == null) { gg.setColor(Color.RED); gg.drawLine(x+1, bottom+1, right+1, y+1); } else { gg.setColor(color); gg.fill(s); } gg.setStroke(new BasicStroke(1)); gg.setColor(new Color(232, 232, 232)); gg.draw(s); } } private @NotNull String toPosition(int position) { switch (position) { case POSITION_FIRST: return "first"; case POSITION_MIDDLE: return "middle"; case POSITION_LAST: return "last"; default: return "only"; } } private Icon createDefaultIcon() { String imageName = "NSImage://NSActionTemplate"; Image im = Toolkit.getDefaultToolkit().getImage(imageName); if (im != null) { return new ImageIcon(im); } System.err.println("Unable to load image: " + imageName); return null; } }