All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdesktop.layout.AquaLayoutStyle Maven / Gradle / Ivy

Go to download

Swing Layout Extensions goal is to make it easy to create professional cross platform layouts with Swing. This project has an eye towards the needs of GUI builders, such as NetBeans. This project consists of the following pieces: * Ability to get the baseline for components. * Ability to get the preferred gap between components. * A new LayoutManager that utilizes both of these concepts and is tuned toward a free-form drag and drop layout model as can be provided by GUI builders.

There is a newer version: 1.0.2
Show newest version
/*
 * Copyright (C) 2005 Sun Microsystems, Inc. All rights reserved. Use is
 * subject to license terms.
 */ 

package org.jdesktop.layout;

import javax.swing.border.EmptyBorder;
import org.jdesktop.layout.*;
import java.awt.*;
import java.lang.reflect.*;
import javax.swing.*;
import java.util.*;

/**
 * An implementation of LayoutStyle for Mac OS X Tiger.
 * 

* The information used for this layout style comes from: * http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/ * * @author Werner Randelshofer * @version $Revision: 1.2 $ */ class AquaLayoutStyle extends LayoutStyle { private static final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0); /** Mini size style. */ private final static int MINI = 0; /** Small size style. */ private final static int SMALL = 1; /** Regular size style. */ private final static int REGULAR = 2; /** * The containerGapDefinitions array defines the preferred insets (child gaps) * of a parent container towards one of its child components. * * Note: As of now, we do not yet specify the preferred gap from a child * to its parent. Therefore we may not be able to treat all special cases. * * This array is used to initialize the containerGaps HashMap. * * The array has the following structure, which is supposed to be a * a compromise between legibility and code size. * containerGapDefinitions[0..n] = preferred insets for some parent UI's * containerGapDefinitions[][0..m-3] = name of parent UI, * optionally followed by a full stop and * a style name * containerGapDefinitions[][m-2] = mini insets * containerGapDefinitions[][m-1] = small insets * containerGapDefinitions[][m] = regular insets */ private final static Object[][] containerGapDefinitions = { // Format: // { list of parent UI's, // mini insets, small insets, regular insets } { "TabbedPaneUI", new Insets(6,10,10,10), new Insets(6,10,10,12), new Insets(12,20,20,20) }, // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGLayout/chapter_19_section_3.html#//apple_ref/doc/uid/TP30000360/DontLinkElementID_27 // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGLayout/chapter_19_section_3.html#//apple_ref/doc/uid/TP30000360/DontLinkElementID_26 // note for small and mini size: leave 8 to 10 pixels on top // note for regular size: leave only 12 pixel at top if tabbed pane UI { "RootPaneUI", new Insets(8,10,10,10), new Insets(8,10,10,12), new Insets(14,20,20,20) }, // These child gaps are used for all other components { "default", new Insets(8,10,10,10), new Insets(8,10,10,12), new Insets(14,20,20,20) }, }; /** * The relatedGapDefinitions table defines the preferred gaps * of one party of two related components. * * The effective preferred gap is the maximum of the preferred gaps of * both parties. * * This array is used to initialize the relatedGaps HashMap. * * The array has the following structure, which is supposed to be a * a compromise between legibility and code size. * containerGapDefinitions[0..n] = preferred gaps for a party of a two related UI's * containerGapDefinitions[][0..m-3] = name of UI * optionally followed by a full stop and * a style name * containerGapDefinitions[][m-2] = mini insets * containerGapDefinitions[][m-1] = small insets * containerGapDefinitions[][m] = regular insets */ private final static Object[][] relatedGapDefinitions = { // Format: // { list of UI's, // mini insets, small insets, regular insets } // Push Button: // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_2.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF104 { "ButtonUI", "ButtonUI.push", "ButtonUI.text", "ToggleButtonUI.push", "ToggleButtonUI.text", new Insets(8,8,8,8), new Insets(10,10,10,10), new Insets(12,12,12,12) }, // Metal Button // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_2.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF187 { "ButtonUI.metal", "ToggleButtonUI.metal", new Insets(8,8,8,8), new Insets(8,8,8,8), new Insets(12,12,12,12) }, // Bevel Button (Rounded and Square) // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_2.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF112 { "ButtonUI.bevel", "ButtonUI.toggle", "ButtonUI.square", "ToggleButtonUI", "ToggleButtonUI.bevel", "ToggleButtonUI.square", "ToggleButtonUI.toggle", new Insets(0,0,0,0), new Insets(0,0,0,0), new Insets(0,0,0,0) }, // Bevel Button (Rounded and Square) // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_2.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF112 { "ButtonUI.bevel.largeIcon", "ToggleButtonUI.bevel.largeIcon", new Insets(8,8,8,8), new Insets(8,8,8,8), new Insets(8,8,8,8) }, // Icon Button // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_2.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF189 { "ButtonUI.icon", new Insets(0,0,0,0), new Insets(0,0,0,0), new Insets(0,0,0,0) }, { "ButtonUI.icon.largeIcon", new Insets(8,8,8,8), new Insets(8,8,8,8), new Insets(8,8,8,8) }, // Round Button // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_2.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF191 { "ButtonUI.round", "ToggleButtonUI.round", new Insets(12,12,12,12), new Insets(12,12,12,12), new Insets(12,12,12,12) }, // Help Button // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_2.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF193 { "ButtonUI.help", new Insets(12,12,12,12), new Insets(12,12,12,12), new Insets(12,12,12,12) }, // Segmented Control // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_3.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF196 { "ButtonUI.toggleCenter", "ToggleButtonUI.toggleCenter", new Insets(8,0,8,0), new Insets(10,0,10,0), new Insets(12,0,12,0) }, { "ButtonUI.toggleEast", "ToggleButtonUI.toggleEast", new Insets(8,0,8,8), new Insets(10,0,10,10), new Insets(12,0,12,12) }, { "ButtonUI.toggleWest", "ToggleButtonUI.toggleWest", new Insets(8,8,8,0), new Insets(10,10,10,0), new Insets(12,12,12,0) }, { "ButtonUI.toolBarTab", "ToggleButtonUI.toolBarTab", new Insets(0,0,0,0), new Insets(0,0,0,0), new Insets(0,0,0,0) }, // Color Well Button // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_3.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF213 { "ButtonUI.colorWell", "ToggleButtonUI.colorWell", new Insets(0,0,0,0), new Insets(0,0,0,0), new Insets(0,0,0,0) }, // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_3.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF198 // FIXME - The following values are given in the AHIG. // In reality, the values further below seem to be more appropriate. // Which ones are right? //{ "CheckBoxUI", new Insets(7, 5, 7, 5), new Insets(8, 6, 8, 6), new Insets(8, 8, 8, 8) }, { "CheckBoxUI", new Insets(6, 5, 6, 5), new Insets(7, 6, 7, 6), new Insets(7, 6, 7, 6) }, // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_3.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF198 { "ComboBoxUI", new Insets(8, 5, 8, 5), new Insets(10, 6, 10, 6), new Insets(12, 8, 12, 8) }, // There is no spacing given for labels. // This comes from playing with IB. // We use the values here, which is the minimum of the spacing of all // other components. { "LabelUI", new Insets(8, 8, 8, 8), new Insets(8, 8, 8, 8), new Insets(8, 8, 8, 8) }, // ? spacing not given { "ListUI", new Insets(5, 5, 5, 5), new Insets(6, 6, 6, 6), new Insets(6, 6, 6, 6) }, // ? spacing not given { "PanelUI", new Insets(0, 0, 0, 0), new Insets(0, 0, 0, 0), new Insets(0, 0, 0, 0) }, // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_5.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF106 // ? spacing not given { "ProgressBarUI", new Insets(8,8,8,8), new Insets(10,10,10,10), new Insets(12,12,12,12) }, // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_3.html#//apple_ref/doc/uid/20000957-TP30000359-BIAHBFAD { "RadioButtonUI", new Insets(5, 5, 5, 5), new Insets(6, 6, 6, 6), new Insets(6, 6, 6, 6) }, //http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_6.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF114 // ? spacing not given. We use the same as for text fields. { "ScrollPaneUI", new Insets(6, 8, 6, 8), new Insets(6, 8, 6, 8), new Insets(8, 10, 8, 10) }, //http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_8.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF214 // ? spacing not given //http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGLayout/chapter_19_section_2.html#//apple_ref/doc/uid/20000957-TP30000360-CHDEACGD { "SeparatorUI", new Insets(8, 8, 8, 8), new Insets(10, 10, 10, 10), new Insets(12, 12, 12, 12) }, // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_4.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF115 { "SliderUI.horizontal", new Insets(8,8,8,8), new Insets(10,10,10,10), new Insets(12,12,12,12) }, { "SliderUI.vertical", new Insets(8,8,8,8), new Insets(10,10,10,10), new Insets(12,12,12,12) }, //http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_4.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF204 { "SpinnerUI", new Insets(6, 8, 6, 8), new Insets(6, 8, 6, 8), new Insets(8, 10, 8, 10) }, // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_7.html#//apple_ref/doc/uid/20000957-TP30000359-CHDDBIJE // ? spacing not given { "SplitPaneUI", new Insets(0,0,0,0), new Insets(0,0,0,0), new Insets(0,0,0,0) }, // http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_7.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF105 // ? spacing not given { "TabbedPaneUI", new Insets(0,0,0,0), new Insets(0,0,0,0), new Insets(0,0,0,0) }, { "TableUI", new Insets(0,0,0,0), new Insets(0,0,0,0), new Insets(0,0,0,0) }, // ? spacing not given { "TextAreaUI", "EditorPaneUI", "TextPaneUI", new Insets(0,0,0,0), new Insets(0,0,0,0), new Insets(0,0,0,0) }, //http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGControls/chapter_18_section_6.html#//apple_ref/doc/uid/20000957-TP30000359-TPXREF225 { "TextFieldUI", "FormattedTextFieldUI", "PasswordFieldUI", new Insets(6, 8, 6, 8), new Insets(6, 8, 6, 8), new Insets(8, 10, 8, 10) }, // ? spacing not given { "TreeUI", new Insets(0,0,0,0), new Insets(0,0,0,0), new Insets(0,0,0,0) }, }; private final static Object[][] unrelatedGapDefinitions = { // UI, mini, small, regular { "ButtonUI.help", new Insets(24,24,24,24), new Insets(24,24,24,24), new Insets(24,24,24,24) }, { "default", new Insets(10, 10, 10, 10), new Insets(12, 12, 12, 12), new Insets(14, 14, 14, 14) }, }; /** * The indentGapDefinitions table defines the preferred indentation * for components that are indented after the specified component. * * This array is used to initialize the indentGaps HashMap. * * The array has the following structure, which is supposed to be a * a compromise between legibility and code size. * indentGapDefinitions[0..n] = preferred gaps for a party of a two related UI's * indentGapDefinitions[][0..m-3] = name of UI * optionally followed by a full stop and * a style name * indentGapDefinitions[][m-2] = mini insets * indentGapDefinitions[][m-1] = small insets * indentGapDefinitions[][m] = regular insets */ private final static Object[][] indentGapDefinitions = { // UI, mini, small, regular // The Aqua L&F does not scale button images of check boxes and radio // buttons. Therefore we use to the same horizontal indents for all sizes. { "CheckBoxUI", "RadioButtonUI", new Insets(16, 24, 16, 24), new Insets(20, 24, 20, 24), new Insets(24, 24, 24, 24) }, { "default", new Insets(16, 16, 16, 16), new Insets(20, 20, 20, 20), new Insets(24, 24, 24, 24) }, }; /** * The visualMarginDefinition table defines the visually perceived * margin of the components. * * This array is used to initialize the visualMargins HashMap. * * The array has the following structure, which is supposed to be a * a compromise between legibility and code size. * visualMarginDefinitions[0..n] = preferred gaps for a party of a two related UI's * visualMarginDefinitions[][0..m-1] = name of UI * optionally followed by a full stop and * a style name * containerGapDefinitions[][m] = visual margins */ private final static Object[][] visualMarginDefinitions = { // UI, regular { "ButtonUI", "ButtonUI.text", "ToggleButtonUI", "ToggleButtonUI.text", new Insets(5, 3, 3, 3) }, { "ButtonUI.icon", "ToggleButtonUI.icon", new Insets(5, 2, 3, 2) }, { "ButtonUI.toolbar", "ToggleButtonUI.toolbar", new Insets(0, 0, 0, 0) }, { "CheckBoxUI", new Insets(4, 4, 3, 3) }, { "ComboBoxUI", new Insets(2, 3, 4, 3) }, { "DesktopPaneUI", new Insets(0, 0, 0, 0) }, { "EditorPaneUI", "TextAreaUI", "TextPaneUI", new Insets(0, 0, 0, 0) }, { "FormattedTextFieldUI", "PasswordFieldUI", "TextFieldUI", new Insets(0, 0, 0, 0) }, { "LabelUI", new Insets(0, 0, 0, 0) }, { "ListUI", new Insets(0, 0, 0, 0) }, { "PanelUI", new Insets(0, 0, 0, 0) }, { "ProgressBarUI", "ProgressBarUI.horizontal", new Insets(0, 2, 4, 2) }, { "ProgressBarUI.vertical", new Insets(2, 0, 2, 4) }, { "RadioButtonUI", new Insets(4, 4, 3, 3) }, { "ScrollBarUI", new Insets(0, 0, 0, 0) }, { "ScrollPaneUI", new Insets(0, 0, 0, 0) }, { "SpinnerUI", new Insets(0, 0, 0, 0) }, { "SeparatorUI", new Insets(0, 0, 0, 0) }, { "SplitPaneUI", new Insets(0, 0, 0, 0) }, { "SliderUI", "SliderUI.horizontal", new Insets(3, 6, 3, 6) }, { "SliderUI.vertical", new Insets(6, 3, 6, 3) }, { "TabbedPaneUI", "TabbedPaneUI.top", new Insets(5, 7, 10, 7) }, { "TabbedPaneUI.bottom", new Insets(4, 7, 5, 7) }, { "TabbedPaneUI.left", new Insets(4, 6, 10, 7) }, { "TabbedPaneUI.right", new Insets(4, 7, 10, 6) }, { "TableUI", new Insets(0, 0, 0, 0) }, { "TreeUI", new Insets(0, 0, 0, 0) }, { "default", new Insets(0, 0, 0, 0) }, }; /** * The relatedGaps map defines the preferred gaps * of one party of two related components. */ private final static Map RELATED_GAPS = createInsetsMap(relatedGapDefinitions); /** * The unrelatedGaps map defines the preferred gaps * of one party of two unrelated components. */ private final static Map UNRELATED_GAPS = createInsetsMap(unrelatedGapDefinitions); /** * The containerGaps map defines the preferred insets (child gaps) * of a parent component towards one of its children. */ private final static Map CONTAINER_GAPS = createInsetsMap(containerGapDefinitions); /** * The indentGaps map defines the preferred indentation * for components that are indented after the specified component. */ private final static Map INDENT_GAPS = createInsetsMap(indentGapDefinitions); /** * The visualMargins map defines the preferred indentation * for components that are indented after the specified component. */ private final static Map VISUAL_MARGINS = createInsetsMap(visualMarginDefinitions); /** * Creates a map for the specified definitions array. *

* The key for the map is the name of the UI, for example, ButtonUI, with * a value of ComponentInsets. Each ComponentInsets may have sub styles. */ // private static Map createInsetsMap(Object[][] definitions) { private static Map createInsetsMap(Object[][] definitions) { Map map = new HashMap(); for (int i=0; i < definitions.length; i++) { int keys = 0; while (keys < definitions[i].length && (definitions[i][keys] instanceof String)) { keys++; } Insets[] values = new Insets[definitions[i].length - keys]; for (int j=keys; j < definitions[i].length; j++) { values[j-keys] = (Insets) definitions[i][j]; } for (int j=0; j < keys; j++) { String key = (String)definitions[i][j]; int subindex = key.indexOf('.'); if (subindex == -1) { ComponentInsets componentInsets = (ComponentInsets)map.get(key); if (componentInsets == null) { componentInsets = new ComponentInsets(values); map.put(key, new ComponentInsets(values)); } else { assert (componentInsets.getInsets() == null); componentInsets.setInsets(values); } } else { String subkey = key.substring(subindex + 1); String parentKey = key.substring(0, subindex); ComponentInsets componentInsets = (ComponentInsets) map.get(parentKey); if (componentInsets == null) { componentInsets = new ComponentInsets(); map.put(parentKey, componentInsets); } componentInsets.addSubinsets(subkey, new ComponentInsets(values)); } } } return map; } public static void main(String[] args) { JButton button = new JButton(); button.putClientProperty("JButton.buttonType", "metal"); JButton button2 = new JButton(); LayoutStyle style = new AquaLayoutStyle(); int gap = style.getPreferredGap(button, button2, LayoutStyle.RELATED, SwingConstants.EAST, null); System.err.println("gap= " + gap); button.putClientProperty("JButton.buttonType", "square"); button2.putClientProperty("JButton.buttonType", "square"); gap = style.getPreferredGap(button, button2, LayoutStyle.RELATED, SwingConstants.EAST, null); System.err.println("gap= " + gap); } /** * Creates a new instance. */ public AquaLayoutStyle() { } /** * Returns the amount of space to use between two components. * The return value indicates the distance to place * component2 relative to component1. * For example, the following returns the amount of space to place * between component2 and component1 * when component2 is placed vertically above * component1: *

     *   int gap = getPreferredGap(component1, component2,
     *                             LayoutStyle.RELATED,
     *                             SwingConstants.NORTH, parent);
     * 
* The type parameter indicates the type * of gap being requested. It can be one of the following values: * *
RELATED * If the two components will be contained in * the same parent and are showing similar logically related * items, use RELATED. *
UNRELATED * If the two components will be * contained in the same parent but show logically unrelated items * use UNRELATED. *
INDENT * Used to obtain the preferred distance to indent a component * relative to another. For example, if you want to horizontally * indent a JCheckBox relative to a JLabel use INDENT. * This is only useful for the horizontal axis. *
*

* It's important to note that some look and feels may not distinguish * between RELATED and UNRELATED. *

* The return value is not intended to take into account the * current size and position of component2 or * component1. The return value may take into * consideration various properties of the components. For * example, the space may vary based on font size, or the preferred * size of the component. * * @param component1 the JComponent * component2 is being placed relative to * @param component2 the JComponent being placed * @param type how the two components are being placed * @param position the position component2 is being placed * relative to component1; one of * SwingConstants.NORTH, * SwingConstants.SOUTH, * SwingConstants.EAST or * SwingConstants.WEST * @param parent the parent of component2; this may differ * from the actual parent and may be null * @return the amount of space to place between the two components * @throws IllegalArgumentException if position is not * one of SwingConstants.NORTH, * SwingConstants.SOUTH, * SwingConstants.EAST or * SwingConstants.WEST; type not one * of INDENT, RELATED * or UNRELATED; or component1 or * component2 is null */ public int getPreferredGap(JComponent component1, JComponent component2, int type, int position, Container parent) { // Check args super.getPreferredGap(component1, component2, type, position, parent); int result; // Compute gap if (type == INDENT) { // Compute gap if (position == SwingConstants.EAST || position == SwingConstants.WEST) { int gap = getButtonChildIndent(component1, position); if (gap != 0) { return gap; } } int sizeStyle = getSizeStyle(component1); Insets gap1 = getPreferredGap(component1, type, sizeStyle); switch (position) { case SwingConstants.NORTH : result = gap1.bottom; break; case SwingConstants.SOUTH : result = gap1.top; break; case SwingConstants.EAST : result = gap1.left; break; case SwingConstants.WEST : default : result = gap1.right; break; } int raw = result; // Compensate for visual margin Insets visualMargin2 = getVisualMargin(component2); switch (position) { case SwingConstants.NORTH : result -= visualMargin2.bottom; break; case SwingConstants.SOUTH : result -= visualMargin2.top; break; case SwingConstants.EAST : result -= visualMargin2.left; break; case SwingConstants.WEST : result -= visualMargin2.right; default : break; } } else { // Compute gap int sizeStyle = Math.min(getSizeStyle(component1), getSizeStyle(component2)); Insets gap1 = getPreferredGap(component1, type, sizeStyle); Insets gap2 = getPreferredGap(component2, type, sizeStyle); switch (position) { case SwingConstants.NORTH : result = Math.max(gap1.top, gap2.bottom); break; case SwingConstants.SOUTH : result = Math.max(gap1.bottom, gap2.top); break; case SwingConstants.EAST : result = Math.max(gap1.right, gap2.left); break; case SwingConstants.WEST : default : result = Math.max(gap1.left, gap2.right); break; } // Compensate for visual margin Insets visualMargin1 = getVisualMargin(component1); Insets visualMargin2 = getVisualMargin(component2); switch (position) { case SwingConstants.NORTH : result -= visualMargin1.top + visualMargin2.bottom; break; case SwingConstants.SOUTH : result -= visualMargin1.bottom + visualMargin2.top; break; case SwingConstants.EAST : result -= visualMargin1.right + visualMargin2.left; break; case SwingConstants.WEST : result -= visualMargin1.left + visualMargin2.right; default : break; } } // Aqua does not support negative gaps, because all its components are // opaque return Math.max(0, result); } private Insets getPreferredGap(JComponent component, int type, int sizeStyle) { Map gapMap; switch (type) { case INDENT : gapMap = INDENT_GAPS; break; case RELATED : gapMap = RELATED_GAPS; break; case UNRELATED : default : gapMap = UNRELATED_GAPS; break; } String uid = component.getUIClassID(); String style = null; // == is ok here as Strings from Swing get interned, if for some reason // need .equals then must deal with null. if (uid == "ButtonUI" || uid =="ToggleButtonUI") { style = (String) component.getClientProperty("JButton.buttonType"); } else if (uid =="ProgressBarUI") { style = (((JProgressBar) component).getOrientation() == JProgressBar.HORIZONTAL) ? "horizontal" : "vertical"; } else if (uid == "SliderUI") { style = (((JSlider) component).getOrientation() == JProgressBar.HORIZONTAL) ? "horizontal" : "vertical"; } else if (uid == "TabbedPaneUI") { switch (((JTabbedPane) component).getTabPlacement()) { case JTabbedPane.TOP : style = "top"; break; case JTabbedPane.LEFT : style = "left"; break; case JTabbedPane.BOTTOM : style = "bottom"; break; case JTabbedPane.RIGHT : style = "right"; break; } } return getInsets(gapMap, uid, style, sizeStyle); } /** * Returns the amount of space to position a component inside its * parent. * * @param component the Component being positioned * @param position the position component is being placed * relative to its parent; one of * SwingConstants.NORTH, * SwingConstants.SOUTH, * SwingConstants.EAST or * SwingConstants.WEST * @param parent the parent of component; this may differ * from the actual parent and may be null * @return the amount of space to place between the component and specified * edge * @throws IllegalArgumentException if position is not * one of SwingConstants.NORTH, * SwingConstants.SOUTH, * SwingConstants.EAST or * SwingConstants.WEST; * or component is null */ public int getContainerGap(JComponent component, int position, Container parent) { int result; int sizeStyle = Math.min(getSizeStyle(component), getSizeStyle(parent)); // Compute gap Insets gap = getContainerGap(parent, sizeStyle); switch (position) { case SwingConstants.NORTH : result = gap.top; break; case SwingConstants.SOUTH : result = gap.bottom; break; case SwingConstants.EAST : result = gap.right; break; case SwingConstants.WEST : default : result = gap.left; break; } // Compensate for visual margin Insets visualMargin = getVisualMargin(component); switch (position) { case SwingConstants.NORTH : result -= visualMargin.top; break; case SwingConstants.SOUTH : result -= visualMargin.bottom; // Radio buttons in Quaqua are 1 pixel too high, in order // to align their baselines with other components, when no // baseline aware layout manager is used. if (component instanceof JRadioButton) { result--; } break; case SwingConstants.EAST : result -= visualMargin.left; break; case SwingConstants.WEST : result -= visualMargin.right; default : break; } // Aqua does not support negative gaps, because all its components are // opaque return Math.max(0, result); } private Insets getContainerGap(Container container, int sizeStyle) { String uid; if (container instanceof JComponent) { uid = ((JComponent) container).getUIClassID(); } else if (container instanceof Dialog) { uid = "Dialog"; } else if (container instanceof Frame) { uid = "Frame"; } else if (container instanceof java.applet.Applet) { uid = "Applet"; } else if (container instanceof Panel) { uid = "Panel"; } else { uid = "default"; } // FIXME insert style code here for JInternalFrame with palette style return getInsets(CONTAINER_GAPS, uid, null, sizeStyle); } private Insets getInsets(Map gapMap, String uid, String style, int sizeStyle) { if (uid == null) { uid = "default"; } ComponentInsets componentInsets = (ComponentInsets)gapMap.get(uid); if (componentInsets == null) { componentInsets = (ComponentInsets)gapMap.get("default"); if (componentInsets == null) { return EMPTY_INSETS; } } else if (style != null) { ComponentInsets subInsets = componentInsets.getSubinsets(style); if (subInsets != null) { componentInsets = subInsets; } } return componentInsets.getInsets(sizeStyle); } private Insets getVisualMargin(JComponent component) { String uid = component.getUIClassID(); String style = null; if (uid == "ButtonUI" || uid == "ToggleButtonUI") { style = (String) component.getClientProperty("JButton.buttonType"); } else if (uid == "ProgressBarUI") { style = (((JProgressBar) component).getOrientation() == JProgressBar.HORIZONTAL) ? "horizontal" : "vertical"; } else if (uid == "SliderUI") { style = (((JSlider) component).getOrientation() == JProgressBar.HORIZONTAL) ? "horizontal" : "vertical"; } else if (uid == "TabbedPaneUI") { switch (((JTabbedPane) component).getTabPlacement()) { case JTabbedPane.TOP : style = "top"; break; case JTabbedPane.LEFT : style = "left"; break; case JTabbedPane.BOTTOM : style = "bottom"; break; case JTabbedPane.RIGHT : style = "right"; break; } } Insets gap = getInsets(VISUAL_MARGINS, uid, style, 0); // Take into account different positions of the button icon if (uid == "RadioButtonUI" || uid == "CheckBoxUI") { switch (((AbstractButton) component).getHorizontalTextPosition()) { case SwingConstants.RIGHT : gap = new Insets(gap.top, gap.right, gap.bottom, gap.left); break; case SwingConstants.CENTER : gap = new Insets(gap.top, gap.right, gap.bottom, gap.right); break; /* case SwingConstants.LEFT : break; */ } if (component.getBorder() instanceof EmptyBorder) { gap.left -= 2; gap.right -= 2; gap.top -= 2; gap.bottom -= 2; } } return gap; } /** * Returns the size style of a specified component. * * @return REGULAR, SMALL or MINI. */ private int getSizeStyle(Component c) { // Aqua components have a different style depending on the // font size used. // 13 Point = Regular // 11 Point = Small // 9 Point = Mini if (c == null) { return REGULAR; } Font font = c.getFont(); if (font == null) { return REGULAR; } int fontSize = font.getSize(); return (fontSize >= 13) ? REGULAR : ((fontSize > 9) ? SMALL : MINI); } /** * ComponentInsets is used to manage the Insets for a specific Component * type. Each ComponentInsets may also have children (sub) ComponentInsets. * Subinsets are used to represent different styles a component may have. * For example, a Button may not a set of insets, as well as insets when * it has a style of metal. */ private static class ComponentInsets { // Map private Map children; private Insets[] insets; public ComponentInsets() { } public ComponentInsets(Insets[] insets) { this.insets = insets; } public void setInsets(Insets[] insets) { this.insets = insets; } public Insets[] getInsets() { return insets; } public Insets getInsets(int size) { if (insets == null) { return EMPTY_INSETS; } return insets[size]; } void addSubinsets(String subkey, ComponentInsets subinsets) { if (children == null) { children = new HashMap(5); } children.put(subkey, subinsets); } ComponentInsets getSubinsets(String subkey) { return (children == null) ? null : (ComponentInsets)children.get(subkey); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy