84 * <p>The values are only read out of UIManager once, and then cached. If
85 * you need to read the values again (for example, if the UI is being reloaded),
86 * then discard this NimbusStyle and read a new one from NimbusLookAndFeel
87 * using NimbusLookAndFeel.getStyle.</p>
88 *
89 * <p>The primary API of interest in this class for 3rd party component authors
90 * are the three methods which retrieve painters: #getBackgroundPainter,
91 * #getForegroundPainter, and #getBorderPainter.</p>
92 *
93 * <p>NimbusStyle allows you to specify custom states, or modify the order of
94 * states. Synth (and thus Nimbus) has the concept of a "state". For example,
95 * a JButton might be in the "MOUSE_OVER" state, or the "ENABLED" state, or the
96 * "DISABLED" state. These are all "standard" states which are defined in synth,
97 * and which apply to all synth Regions.</p>
98 *
99 * <p>Sometimes, however, you need to have a custom state. For example, you
100 * want JButton to render differently if it's parent is a JToolbar. In Nimbus,
101 * you specify these custom states by including a special key in UIDefaults.
102 * The following UIDefaults entries define three states for this button:</p>
103 *
104 * <pre><code>
105 * JButton.States = Enabled, Disabled, Toolbar
106 * JButton[Enabled].backgroundPainter = somePainter
107 * JButton[Disabled].background = BLUE
108 * JButton[Toolbar].backgroundPainter = someOtherPaint
109 * </code></pre>
110 *
111 * <p>As you can see, the <code>JButton.States</code> entry lists the states
112 * that the JButton style will support. You then specify the settings for
113 * each state. If you do not specify the <code>JButton.States</code> entry,
114 * then the standard Synth states will be assumed. If you specify the entry
115 * but the list of states is empty or null, then the standard synth states
116 * will be assumed.</p>
117 *
118 * @author Richard Bair
119 * @author Jasper Potts
120 */
121 public final class NimbusStyle extends SynthStyle {
122 /* Keys and scales for large/small/mini components, based on Apples sizes */
123 /** Large key */
124 public static final String LARGE_KEY = "large";
125 /** Small key */
126 public static final String SMALL_KEY = "small";
127 /** Mini key */
128 public static final String MINI_KEY = "mini";
129 /** Large scale */
130 public static final double LARGE_SCALE = 1.15;
131 /** Small scale */
132 public static final double SMALL_SCALE = 0.857;
133 /** Mini scale */
134 public static final double MINI_SCALE = 0.714;
135
136 /**
137 * Special constant used for performance reasons during the get() method.
138 * If get() runs through all of the search locations and determines that
139 * there is no value, then NULL will be placed into the values map. This way
140 * on subsequent lookups it will simply extract NULL, see it, and return
141 * null rather than continuing the lookup procedure.
142 */
143 private static final Object NULL = '\0';
144 /**
145 * <p>The Color to return from getColorForState if it would otherwise have
146 * returned null.</p>
147 *
148 * <p>Returning null from getColorForState is a very bad thing, as it causes
149 * the AWT peer for the component to install a SystemColor, which is not a
150 * UIResource. As a result, if <code>null</code> is returned from
151 * getColorForState, then thereafter the color is not updated for other
152 * states or on LAF changes or updates. This DEFAULT_COLOR is used to
153 * ensure that a ColorUIResource is always returned from
154 * getColorForState.</p>
155 */
156 private static final Color DEFAULT_COLOR = new ColorUIResource(Color.BLACK);
157 /**
158 * Simple Comparator for ordering the RuntimeStates according to their
159 * rank.
160 */
161 private static final Comparator<RuntimeState> STATE_COMPARATOR =
162 new Comparator<RuntimeState>() {
163 @Override
164 public int compare(RuntimeState a, RuntimeState b) {
165 return a.state - b.state;
166 }
167 };
168 /**
169 * The prefix for the component or region that this NimbusStyle
170 * represents. This prefix is used to lookup state in the UIManager.
906 xstate |= mask;
907 }
908 mask <<= 1;
909 }
910 }
911 return xstate;
912 }
913
914 /**
915 * <p>Gets the RuntimeState that most closely matches the state in the given
916 * context, but is less specific than the given "lastState". Essentially,
917 * this allows you to search for the next best state.</p>
918 *
919 * <p>For example, if you had the following three states:
920 * <pre>
921 * Enabled
922 * Enabled+Pressed
923 * Disabled
924 * </pre>
925 * And you wanted to find the state that best represented
926 * ENABLED+PRESSED+FOCUSED and <code>lastState</code> was null (or an
927 * empty array, or an array with a single int with index == -1), then
928 * Enabled+Pressed would be returned. If you then call this method again but
929 * pass the index of Enabled+Pressed as the "lastState", then
930 * Enabled would be returned. If you call this method a third time and pass
931 * the index of Enabled in as the <code>lastState</code>, then null would be
932 * returned.</p>
933 *
934 * <p>The actual code path for determining the proper state is the same as
935 * in Synth.</p>
936 *
937 * @param ctx
938 * @param lastState a 1 element array, allowing me to do pass-by-reference.
939 * @return
940 */
941 private RuntimeState getNextState(RuntimeState[] states,
942 int[] lastState,
943 int xstate) {
944 // Use the StateInfo with the most bits that matches that of state.
945 // If there are none, then fallback to
946 // the StateInfo with a state of 0, indicating it'll match anything.
947
948 // Consider if we have 3 StateInfos a, b and c with states:
949 // SELECTED, SELECTED | ENABLED, 0
950 //
951 // Input Return Value
1009 bestIndex = counter;
1010 bestCount = bitCount;
1011 }
1012 }
1013 }
1014 if (bestIndex != -1) {
1015 lastState[0] = bestIndex;
1016 return states[bestIndex];
1017 }
1018 if (wildIndex != -1) {
1019 lastState[0] = wildIndex;
1020 return states[wildIndex];
1021 }
1022 }
1023 lastState[0] = -1;
1024 return null;
1025 }
1026
1027 /**
1028 * Contains values such as the UIDefaults and painters associated with
1029 * a state. Whereas <code>State</code> represents a distinct state that a
1030 * component can be in (such as Enabled), this class represents the colors,
1031 * fonts, painters, etc associated with some state for this
1032 * style.
1033 */
1034 private final class RuntimeState implements Cloneable {
1035 int state;
1036 Painter<Object> backgroundPainter;
1037 Painter<Object> foregroundPainter;
1038 Painter<Object> borderPainter;
1039 String stateName;
1040 UIDefaults defaults = new UIDefaults(10, .7f);
1041
1042 private RuntimeState(int state, String stateName) {
1043 this.state = state;
1044 this.stateName = stateName;
1045 }
1046
1047 @Override
1048 public String toString() {
1049 return stateName;
|
84 * <p>The values are only read out of UIManager once, and then cached. If
85 * you need to read the values again (for example, if the UI is being reloaded),
86 * then discard this NimbusStyle and read a new one from NimbusLookAndFeel
87 * using NimbusLookAndFeel.getStyle.</p>
88 *
89 * <p>The primary API of interest in this class for 3rd party component authors
90 * are the three methods which retrieve painters: #getBackgroundPainter,
91 * #getForegroundPainter, and #getBorderPainter.</p>
92 *
93 * <p>NimbusStyle allows you to specify custom states, or modify the order of
94 * states. Synth (and thus Nimbus) has the concept of a "state". For example,
95 * a JButton might be in the "MOUSE_OVER" state, or the "ENABLED" state, or the
96 * "DISABLED" state. These are all "standard" states which are defined in synth,
97 * and which apply to all synth Regions.</p>
98 *
99 * <p>Sometimes, however, you need to have a custom state. For example, you
100 * want JButton to render differently if it's parent is a JToolbar. In Nimbus,
101 * you specify these custom states by including a special key in UIDefaults.
102 * The following UIDefaults entries define three states for this button:</p>
103 *
104 * <pre>{@code
105 * JButton.States = Enabled, Disabled, Toolbar
106 * JButton[Enabled].backgroundPainter = somePainter
107 * JButton[Disabled].background = BLUE
108 * JButton[Toolbar].backgroundPainter = someOtherPaint
109 * }</pre>
110 *
111 * <p>As you can see, the {@code JButton.States} entry lists the states
112 * that the JButton style will support. You then specify the settings for
113 * each state. If you do not specify the {@code JButton.States} entry,
114 * then the standard Synth states will be assumed. If you specify the entry
115 * but the list of states is empty or null, then the standard synth states
116 * will be assumed.</p>
117 *
118 * @author Richard Bair
119 * @author Jasper Potts
120 */
121 public final class NimbusStyle extends SynthStyle {
122 /* Keys and scales for large/small/mini components, based on Apples sizes */
123 /** Large key */
124 public static final String LARGE_KEY = "large";
125 /** Small key */
126 public static final String SMALL_KEY = "small";
127 /** Mini key */
128 public static final String MINI_KEY = "mini";
129 /** Large scale */
130 public static final double LARGE_SCALE = 1.15;
131 /** Small scale */
132 public static final double SMALL_SCALE = 0.857;
133 /** Mini scale */
134 public static final double MINI_SCALE = 0.714;
135
136 /**
137 * Special constant used for performance reasons during the get() method.
138 * If get() runs through all of the search locations and determines that
139 * there is no value, then NULL will be placed into the values map. This way
140 * on subsequent lookups it will simply extract NULL, see it, and return
141 * null rather than continuing the lookup procedure.
142 */
143 private static final Object NULL = '\0';
144 /**
145 * <p>The Color to return from getColorForState if it would otherwise have
146 * returned null.</p>
147 *
148 * <p>Returning null from getColorForState is a very bad thing, as it causes
149 * the AWT peer for the component to install a SystemColor, which is not a
150 * UIResource. As a result, if {@code null} is returned from
151 * getColorForState, then thereafter the color is not updated for other
152 * states or on LAF changes or updates. This DEFAULT_COLOR is used to
153 * ensure that a ColorUIResource is always returned from
154 * getColorForState.</p>
155 */
156 private static final Color DEFAULT_COLOR = new ColorUIResource(Color.BLACK);
157 /**
158 * Simple Comparator for ordering the RuntimeStates according to their
159 * rank.
160 */
161 private static final Comparator<RuntimeState> STATE_COMPARATOR =
162 new Comparator<RuntimeState>() {
163 @Override
164 public int compare(RuntimeState a, RuntimeState b) {
165 return a.state - b.state;
166 }
167 };
168 /**
169 * The prefix for the component or region that this NimbusStyle
170 * represents. This prefix is used to lookup state in the UIManager.
906 xstate |= mask;
907 }
908 mask <<= 1;
909 }
910 }
911 return xstate;
912 }
913
914 /**
915 * <p>Gets the RuntimeState that most closely matches the state in the given
916 * context, but is less specific than the given "lastState". Essentially,
917 * this allows you to search for the next best state.</p>
918 *
919 * <p>For example, if you had the following three states:
920 * <pre>
921 * Enabled
922 * Enabled+Pressed
923 * Disabled
924 * </pre>
925 * And you wanted to find the state that best represented
926 * ENABLED+PRESSED+FOCUSED and {@code lastState} was null (or an
927 * empty array, or an array with a single int with index == -1), then
928 * Enabled+Pressed would be returned. If you then call this method again but
929 * pass the index of Enabled+Pressed as the "lastState", then
930 * Enabled would be returned. If you call this method a third time and pass
931 * the index of Enabled in as the {@code lastState}, then null would be
932 * returned.</p>
933 *
934 * <p>The actual code path for determining the proper state is the same as
935 * in Synth.</p>
936 *
937 * @param ctx
938 * @param lastState a 1 element array, allowing me to do pass-by-reference.
939 * @return
940 */
941 private RuntimeState getNextState(RuntimeState[] states,
942 int[] lastState,
943 int xstate) {
944 // Use the StateInfo with the most bits that matches that of state.
945 // If there are none, then fallback to
946 // the StateInfo with a state of 0, indicating it'll match anything.
947
948 // Consider if we have 3 StateInfos a, b and c with states:
949 // SELECTED, SELECTED | ENABLED, 0
950 //
951 // Input Return Value
1009 bestIndex = counter;
1010 bestCount = bitCount;
1011 }
1012 }
1013 }
1014 if (bestIndex != -1) {
1015 lastState[0] = bestIndex;
1016 return states[bestIndex];
1017 }
1018 if (wildIndex != -1) {
1019 lastState[0] = wildIndex;
1020 return states[wildIndex];
1021 }
1022 }
1023 lastState[0] = -1;
1024 return null;
1025 }
1026
1027 /**
1028 * Contains values such as the UIDefaults and painters associated with
1029 * a state. Whereas {@code State} represents a distinct state that a
1030 * component can be in (such as Enabled), this class represents the colors,
1031 * fonts, painters, etc associated with some state for this
1032 * style.
1033 */
1034 private final class RuntimeState implements Cloneable {
1035 int state;
1036 Painter<Object> backgroundPainter;
1037 Painter<Object> foregroundPainter;
1038 Painter<Object> borderPainter;
1039 String stateName;
1040 UIDefaults defaults = new UIDefaults(10, .7f);
1041
1042 private RuntimeState(int state, String stateName) {
1043 this.state = state;
1044 this.stateName = stateName;
1045 }
1046
1047 @Override
1048 public String toString() {
1049 return stateName;
|