266 for (Object obj : d.keySet()) {
267 if (obj instanceof String) {
268 String key = (String)obj;
269 if (key.startsWith(prefix)) {
270 map.put(key, d.get(key));
271 }
272 }
273 }
274 if (inherit) {
275 defaults.putAll(map);
276 } else {
277 defaults = map;
278 }
279 }
280 }
281
282 //a list of the different types of states used by this style. This
283 //list may contain only "standard" states (those defined by Synth),
284 //or it may contain custom states, or it may contain only "standard"
285 //states but list them in a non-standard order.
286 List<State> states = new ArrayList<State>();
287 //a map of state name to code
288 Map<String,Integer> stateCodes = new HashMap<String,Integer>();
289 //This is a list of runtime "state" context objects. These contain
290 //the values associated with each state.
291 List<RuntimeState> runtimeStates = new ArrayList<RuntimeState>();
292
293 //determine whether there are any custom states, or custom state
294 //order. If so, then read all those custom states and define the
295 //"values" stateTypes to be a non-null array.
296 //Otherwise, let the "values" stateTypes be null to indicate that
297 //there are no custom states or custom state ordering
298 String statesString = (String)defaults.get(prefix + ".States");
299 if (statesString != null) {
300 String s[] = statesString.split(",");
301 for (int i=0; i<s.length; i++) {
302 s[i] = s[i].trim();
303 if (!State.isStandardStateName(s[i])) {
304 //this is a non-standard state name, so look for the
305 //custom state associated with it
306 String stateName = prefix + "." + s[i];
307 State customState = (State)defaults.get(stateName);
308 if (customState != null) {
309 states.add(customState);
310 }
311 } else {
312 states.add(State.getStandardState(s[i]));
313 }
314 }
315
316 //if there were any states defined, then set the stateTypes array
317 //to be non-null. Otherwise, leave it null (meaning, use the
318 //standard synth states).
319 if (states.size() > 0) {
320 values.stateTypes = states.toArray(new State[states.size()]);
321 }
322
323 //assign codes for each of the state types
324 int code = 1;
325 for (State state : states) {
326 stateCodes.put(state.getName(), code);
327 code <<= 1;
328 }
329 } else {
330 //since there were no custom states defined, setup the list of
331 //standard synth states. Note that the "v.stateTypes" is not
332 //being set here, indicating that at runtime the state selection
333 //routines should use standard synth states instead of custom
334 //states. I do need to popuplate this temp list now though, so that
335 //the remainder of this method will function as expected.
336 states.add(State.Enabled);
337 states.add(State.MouseOver);
338 states.add(State.Pressed);
339 states.add(State.Disabled);
340 states.add(State.Focused);
341 states.add(State.Selected);
342 states.add(State.Default);
343
344 //assign codes for the states
345 stateCodes.put("Enabled", ENABLED);
446 if ("backgroundPainter".equals(property)) {
447 rs.backgroundPainter = getPainter(defaults, key);
448 } else if ("foregroundPainter".equals(property)) {
449 rs.foregroundPainter = getPainter(defaults, key);
450 } else if ("borderPainter".equals(property)) {
451 rs.borderPainter = getPainter(defaults, key);
452 } else {
453 rs.defaults.put(property, defaults.get(key));
454 }
455 }
456 }
457
458 //now that I've collected all the runtime states, I'll sort them based
459 //on their integer "state" (see SynthState for how this works).
460 Collections.sort(runtimeStates, STATE_COMPARATOR);
461
462 //finally, set the array of runtime states on the values object
463 values.states = runtimeStates.toArray(new RuntimeState[runtimeStates.size()]);
464 }
465
466 private Painter getPainter(Map<String, Object> defaults, String key) {
467 Object p = defaults.get(key);
468 if (p instanceof UIDefaults.LazyValue) {
469 p = ((UIDefaults.LazyValue)p).createValue(UIManager.getDefaults());
470 }
471 return (p instanceof Painter ? (Painter)p : null);
472 }
473
474 /**
475 * {@inheritDoc}
476 *
477 * Overridden to cause this style to populate itself with data from
478 * UIDefaults, if necessary.
479 */
480 @Override public Insets getInsets(SynthContext ctx, Insets in) {
481 if (in == null) {
482 in = new Insets(0, 0, 0, 0);
483 }
484
485 Values v = getValues(ctx);
486
487 if (v.contentMargins == null) {
488 in.bottom = in.top = in.left = in.right = 0;
489 return in;
490 } else {
491 in.bottom = v.contentMargins.bottom;
672 }
673 // Search Region Defaults
674 if (obj == null && v.defaults != null) {
675 obj = v.defaults.get(partialKey);
676 }
677 // return found object
678 // Search UIManager Defaults
679 if (obj == null) obj = UIManager.get(fullKey);
680 // Search Synth Defaults for InputMaps
681 if (obj == null && partialKey.equals("focusInputMap")) {
682 obj = super.get(ctx, fullKey);
683 }
684 // if all we got was a null, store this fact for later use
685 v.cache.put(new CacheKey(partialKey, xstate),
686 obj == null ? NULL : obj);
687 }
688 // return found object
689 return obj == NULL ? null : obj;
690 }
691
692 /**
693 * Gets the appropriate background Painter, if there is one, for the state
694 * specified in the given SynthContext. This method does appropriate
695 * fallback searching, as described in #get.
696 *
697 * @param ctx The SynthContext. Must not be null.
698 * @return The background painter associated for the given state, or null if
699 * none could be found.
700 */
701 public Painter getBackgroundPainter(SynthContext ctx) {
702 Values v = getValues(ctx);
703 int xstate = getExtendedState(ctx, v);
704 Painter p = null;
705
706 // check the cache
707 tmpKey.init("backgroundPainter$$instance", xstate);
708 p = (Painter)v.cache.get(tmpKey);
709 if (p != null) return p;
710
711 // not in cache, so lookup and store in cache
712 RuntimeState s = null;
713 int[] lastIndex = new int[] {-1};
714 while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
715 if (s.backgroundPainter != null) {
716 p = s.backgroundPainter;
717 break;
718 }
719 }
720 if (p == null) p = (Painter)get(ctx, "backgroundPainter");
721 if (p != null) {
722 v.cache.put(new CacheKey("backgroundPainter$$instance", xstate), p);
723 }
724 return p;
725 }
726
727 /**
728 * Gets the appropriate foreground Painter, if there is one, for the state
729 * specified in the given SynthContext. This method does appropriate
730 * fallback searching, as described in #get.
731 *
732 * @param ctx The SynthContext. Must not be null.
733 * @return The foreground painter associated for the given state, or null if
734 * none could be found.
735 */
736 public Painter getForegroundPainter(SynthContext ctx) {
737 Values v = getValues(ctx);
738 int xstate = getExtendedState(ctx, v);
739 Painter p = null;
740
741 // check the cache
742 tmpKey.init("foregroundPainter$$instance", xstate);
743 p = (Painter)v.cache.get(tmpKey);
744 if (p != null) return p;
745
746 // not in cache, so lookup and store in cache
747 RuntimeState s = null;
748 int[] lastIndex = new int[] {-1};
749 while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
750 if (s.foregroundPainter != null) {
751 p = s.foregroundPainter;
752 break;
753 }
754 }
755 if (p == null) p = (Painter)get(ctx, "foregroundPainter");
756 if (p != null) {
757 v.cache.put(new CacheKey("foregroundPainter$$instance", xstate), p);
758 }
759 return p;
760 }
761
762 /**
763 * Gets the appropriate border Painter, if there is one, for the state
764 * specified in the given SynthContext. This method does appropriate
765 * fallback searching, as described in #get.
766 *
767 * @param ctx The SynthContext. Must not be null.
768 * @return The border painter associated for the given state, or null if
769 * none could be found.
770 */
771 public Painter getBorderPainter(SynthContext ctx) {
772 Values v = getValues(ctx);
773 int xstate = getExtendedState(ctx, v);
774 Painter p = null;
775
776 // check the cache
777 tmpKey.init("borderPainter$$instance", xstate);
778 p = (Painter)v.cache.get(tmpKey);
779 if (p != null) return p;
780
781 // not in cache, so lookup and store in cache
782 RuntimeState s = null;
783 int[] lastIndex = new int[] {-1};
784 while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
785 if (s.borderPainter != null) {
786 p = s.borderPainter;
787 break;
788 }
789 }
790 if (p == null) p = (Painter)get(ctx, "borderPainter");
791 if (p != null) {
792 v.cache.put(new CacheKey("borderPainter$$instance", xstate), p);
793 }
794 return p;
795 }
796
797 /**
798 * Utility method which returns the proper Values based on the given
799 * SynthContext. Ensures that parsing of the values has occurred, or
800 * reoccurs as necessary.
801 *
802 * @param ctx The SynthContext
803 * @return a non-null values reference
804 */
805 private Values getValues(SynthContext ctx) {
806 validate();
807 return values;
808 }
809
810 /**
834 * style information to use for a given state requires a single integer
835 * bit string where each bit in the integer represents a different state
836 * that the component is in. This method uses the componentState as
837 * reported in the SynthContext, in addition to custom states, to determine
838 * what this extended state is.</p>
839 *
840 * <p>In addition, this method checks the component in the given context
841 * for a client property called "Nimbus.State". If one exists, then it will
842 * decompose the String associated with that property to determine what
843 * state to return. In this way, the developer can force a component to be
844 * in a specific state, regardless of what the "real" state of the component
845 * is.</p>
846 *
847 * <p>The string associated with "Nimbus.State" would be of the form:
848 * <pre>Enabled+CustomState+MouseOver</pre></p>
849 *
850 * @param ctx
851 * @param v
852 * @return
853 */
854 private int getExtendedState(SynthContext ctx, Values v) {
855 JComponent c = ctx.getComponent();
856 int xstate = 0;
857 int mask = 1;
858 //check for the Nimbus.State client property
859 //Performance NOTE: getClientProperty ends up inside a synchronized
860 //block, so there is some potential for performance issues here, however
861 //I'm not certain that there is one on a modern VM.
862 Object property = c.getClientProperty("Nimbus.State");
863 if (property != null) {
864 String stateNames = property.toString();
865 String[] states = stateNames.split("\\+");
866 if (v.stateTypes == null){
867 // standard states only
868 for (String stateStr : states) {
869 State.StandardState s = State.getStandardState(stateStr);
870 if (s != null) xstate |= s.getState();
871 }
872 } else {
873 // custom states
874 for (State s : v.stateTypes) {
875 if (contains(states, s.getName())) {
876 xstate |= mask;
877 }
878 mask <<= 1;
879 }
880 }
881 } else {
882 //if there are no custom states defined, then simply return the
883 //state that Synth reported
884 if (v.stateTypes == null) return ctx.getComponentState();
885
886 //there are custom states on this values, so I'll have to iterate
887 //over them all and return a custom extended state
888 int state = ctx.getComponentState();
889 for (State s : v.stateTypes) {
890 if (s.isInState(c, state)) {
891 xstate |= mask;
892 }
893 mask <<= 1;
894 }
1001 return states[bestIndex];
1002 }
1003 if (wildIndex != -1) {
1004 lastState[0] = wildIndex;
1005 return states[wildIndex];
1006 }
1007 }
1008 lastState[0] = -1;
1009 return null;
1010 }
1011
1012 /**
1013 * Contains values such as the UIDefaults and painters associated with
1014 * a state. Whereas <code>State</code> represents a distinct state that a
1015 * component can be in (such as Enabled), this class represents the colors,
1016 * fonts, painters, etc associated with some state for this
1017 * style.
1018 */
1019 private final class RuntimeState implements Cloneable {
1020 int state;
1021 Painter backgroundPainter;
1022 Painter foregroundPainter;
1023 Painter borderPainter;
1024 String stateName;
1025 UIDefaults defaults = new UIDefaults(10, .7f);
1026
1027 private RuntimeState(int state, String stateName) {
1028 this.state = state;
1029 this.stateName = stateName;
1030 }
1031
1032 @Override
1033 public String toString() {
1034 return stateName;
1035 }
1036
1037 @Override
1038 public RuntimeState clone() {
1039 RuntimeState clone = new RuntimeState(state, stateName);
1040 clone.backgroundPainter = backgroundPainter;
1041 clone.foregroundPainter = foregroundPainter;
1042 clone.borderPainter = borderPainter;
1043 clone.defaults.putAll(defaults);
1044 return clone;
1045 }
1046 }
1047
1048 /**
1049 * Essentially a struct of data for a style. A default instance of this
1050 * class is used by NimbusStyle. Additional instances exist for each
1051 * component that has overrides.
1052 */
1053 private static final class Values {
1054 /**
1055 * The list of State types. A State represents a type of state, such
1056 * as Enabled, Default, WindowFocused, etc. These can be custom states.
1057 */
1058 State[] stateTypes = null;
1059 /**
1060 * The list of actual runtime state representations. These can represent things such
1061 * as Enabled + Focused. Thus, they differ from States in that they contain
1062 * several states together, and have associated properties, data, etc.
1063 */
1064 RuntimeState[] states = null;
1065 /**
1066 * The content margins for this region.
1067 */
1068 Insets contentMargins;
1069 /**
1070 * Defaults on the region/component level.
1071 */
1072 UIDefaults defaults = new UIDefaults(10, .7f);
1073 /**
1074 * Simple cache. After a value has been looked up, it is stored
1075 * in this cache for later retrieval. The key is a concatenation of
1076 * the property being looked up, two dollar signs, and the extended
1077 * state. So for example:
1078 *
|
266 for (Object obj : d.keySet()) {
267 if (obj instanceof String) {
268 String key = (String)obj;
269 if (key.startsWith(prefix)) {
270 map.put(key, d.get(key));
271 }
272 }
273 }
274 if (inherit) {
275 defaults.putAll(map);
276 } else {
277 defaults = map;
278 }
279 }
280 }
281
282 //a list of the different types of states used by this style. This
283 //list may contain only "standard" states (those defined by Synth),
284 //or it may contain custom states, or it may contain only "standard"
285 //states but list them in a non-standard order.
286 List<State<?>> states = new ArrayList<>();
287 //a map of state name to code
288 Map<String,Integer> stateCodes = new HashMap<>();
289 //This is a list of runtime "state" context objects. These contain
290 //the values associated with each state.
291 List<RuntimeState> runtimeStates = new ArrayList<>();
292
293 //determine whether there are any custom states, or custom state
294 //order. If so, then read all those custom states and define the
295 //"values" stateTypes to be a non-null array.
296 //Otherwise, let the "values" stateTypes be null to indicate that
297 //there are no custom states or custom state ordering
298 String statesString = (String)defaults.get(prefix + ".States");
299 if (statesString != null) {
300 String s[] = statesString.split(",");
301 for (int i=0; i<s.length; i++) {
302 s[i] = s[i].trim();
303 if (!State.isStandardStateName(s[i])) {
304 //this is a non-standard state name, so look for the
305 //custom state associated with it
306 String stateName = prefix + "." + s[i];
307 State<?> customState = (State)defaults.get(stateName);
308 if (customState != null) {
309 states.add(customState);
310 }
311 } else {
312 states.add(State.getStandardState(s[i]));
313 }
314 }
315
316 //if there were any states defined, then set the stateTypes array
317 //to be non-null. Otherwise, leave it null (meaning, use the
318 //standard synth states).
319 if (states.size() > 0) {
320 values.stateTypes = states.toArray(new State<?>[states.size()]);
321 }
322
323 //assign codes for each of the state types
324 int code = 1;
325 for (State<?> state : states) {
326 stateCodes.put(state.getName(), code);
327 code <<= 1;
328 }
329 } else {
330 //since there were no custom states defined, setup the list of
331 //standard synth states. Note that the "v.stateTypes" is not
332 //being set here, indicating that at runtime the state selection
333 //routines should use standard synth states instead of custom
334 //states. I do need to popuplate this temp list now though, so that
335 //the remainder of this method will function as expected.
336 states.add(State.Enabled);
337 states.add(State.MouseOver);
338 states.add(State.Pressed);
339 states.add(State.Disabled);
340 states.add(State.Focused);
341 states.add(State.Selected);
342 states.add(State.Default);
343
344 //assign codes for the states
345 stateCodes.put("Enabled", ENABLED);
446 if ("backgroundPainter".equals(property)) {
447 rs.backgroundPainter = getPainter(defaults, key);
448 } else if ("foregroundPainter".equals(property)) {
449 rs.foregroundPainter = getPainter(defaults, key);
450 } else if ("borderPainter".equals(property)) {
451 rs.borderPainter = getPainter(defaults, key);
452 } else {
453 rs.defaults.put(property, defaults.get(key));
454 }
455 }
456 }
457
458 //now that I've collected all the runtime states, I'll sort them based
459 //on their integer "state" (see SynthState for how this works).
460 Collections.sort(runtimeStates, STATE_COMPARATOR);
461
462 //finally, set the array of runtime states on the values object
463 values.states = runtimeStates.toArray(new RuntimeState[runtimeStates.size()]);
464 }
465
466 private Painter<Object> getPainter(Map<String, Object> defaults, String key) {
467 Object p = defaults.get(key);
468 if (p instanceof UIDefaults.LazyValue) {
469 p = ((UIDefaults.LazyValue)p).createValue(UIManager.getDefaults());
470 }
471 @SuppressWarnings("unchecked")
472 Painter<Object> tmp = (p instanceof Painter ? (Painter)p : null);
473 return tmp;
474 }
475
476 /**
477 * {@inheritDoc}
478 *
479 * Overridden to cause this style to populate itself with data from
480 * UIDefaults, if necessary.
481 */
482 @Override public Insets getInsets(SynthContext ctx, Insets in) {
483 if (in == null) {
484 in = new Insets(0, 0, 0, 0);
485 }
486
487 Values v = getValues(ctx);
488
489 if (v.contentMargins == null) {
490 in.bottom = in.top = in.left = in.right = 0;
491 return in;
492 } else {
493 in.bottom = v.contentMargins.bottom;
674 }
675 // Search Region Defaults
676 if (obj == null && v.defaults != null) {
677 obj = v.defaults.get(partialKey);
678 }
679 // return found object
680 // Search UIManager Defaults
681 if (obj == null) obj = UIManager.get(fullKey);
682 // Search Synth Defaults for InputMaps
683 if (obj == null && partialKey.equals("focusInputMap")) {
684 obj = super.get(ctx, fullKey);
685 }
686 // if all we got was a null, store this fact for later use
687 v.cache.put(new CacheKey(partialKey, xstate),
688 obj == null ? NULL : obj);
689 }
690 // return found object
691 return obj == NULL ? null : obj;
692 }
693
694 @SuppressWarnings("unchecked")
695 private static Painter<Object> paintFilter(@SuppressWarnings("rawtypes") Painter painter) {
696 return (Painter<Object>) painter;
697 }
698
699
700 /**
701 * Gets the appropriate background Painter, if there is one, for the state
702 * specified in the given SynthContext. This method does appropriate
703 * fallback searching, as described in #get.
704 *
705 * @param ctx The SynthContext. Must not be null.
706 * @return The background painter associated for the given state, or null if
707 * none could be found.
708 */
709 public Painter<Object> getBackgroundPainter(SynthContext ctx) {
710 Values v = getValues(ctx);
711 int xstate = getExtendedState(ctx, v);
712 Painter<Object> p = null;
713
714 // check the cache
715 tmpKey.init("backgroundPainter$$instance", xstate);
716 p = paintFilter((Painter)v.cache.get(tmpKey));
717 if (p != null) return p;
718
719 // not in cache, so lookup and store in cache
720 RuntimeState s = null;
721 int[] lastIndex = new int[] {-1};
722 while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
723 if (s.backgroundPainter != null) {
724 p = paintFilter(s.backgroundPainter);
725 break;
726 }
727 }
728 if (p == null) p = paintFilter((Painter)get(ctx, "backgroundPainter"));
729 if (p != null) {
730 v.cache.put(new CacheKey("backgroundPainter$$instance", xstate), p);
731 }
732 return p;
733 }
734
735 /**
736 * Gets the appropriate foreground Painter, if there is one, for the state
737 * specified in the given SynthContext. This method does appropriate
738 * fallback searching, as described in #get.
739 *
740 * @param ctx The SynthContext. Must not be null.
741 * @return The foreground painter associated for the given state, or null if
742 * none could be found.
743 */
744 public Painter<Object> getForegroundPainter(SynthContext ctx) {
745 Values v = getValues(ctx);
746 int xstate = getExtendedState(ctx, v);
747 Painter<Object> p = null;
748
749 // check the cache
750 tmpKey.init("foregroundPainter$$instance", xstate);
751 p = paintFilter((Painter)v.cache.get(tmpKey));
752 if (p != null) return p;
753
754 // not in cache, so lookup and store in cache
755 RuntimeState s = null;
756 int[] lastIndex = new int[] {-1};
757 while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
758 if (s.foregroundPainter != null) {
759 p = paintFilter(s.foregroundPainter);
760 break;
761 }
762 }
763 if (p == null) p = paintFilter((Painter)get(ctx, "foregroundPainter"));
764 if (p != null) {
765 v.cache.put(new CacheKey("foregroundPainter$$instance", xstate), p);
766 }
767 return p;
768 }
769
770 /**
771 * Gets the appropriate border Painter, if there is one, for the state
772 * specified in the given SynthContext. This method does appropriate
773 * fallback searching, as described in #get.
774 *
775 * @param ctx The SynthContext. Must not be null.
776 * @return The border painter associated for the given state, or null if
777 * none could be found.
778 */
779 public Painter<Object> getBorderPainter(SynthContext ctx) {
780 Values v = getValues(ctx);
781 int xstate = getExtendedState(ctx, v);
782 Painter<Object> p = null;
783
784 // check the cache
785 tmpKey.init("borderPainter$$instance", xstate);
786 p = paintFilter((Painter)v.cache.get(tmpKey));
787 if (p != null) return p;
788
789 // not in cache, so lookup and store in cache
790 RuntimeState s = null;
791 int[] lastIndex = new int[] {-1};
792 while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
793 if (s.borderPainter != null) {
794 p = paintFilter(s.borderPainter);
795 break;
796 }
797 }
798 if (p == null) p = paintFilter((Painter)get(ctx, "borderPainter"));
799 if (p != null) {
800 v.cache.put(new CacheKey("borderPainter$$instance", xstate), p);
801 }
802 return p;
803 }
804
805 /**
806 * Utility method which returns the proper Values based on the given
807 * SynthContext. Ensures that parsing of the values has occurred, or
808 * reoccurs as necessary.
809 *
810 * @param ctx The SynthContext
811 * @return a non-null values reference
812 */
813 private Values getValues(SynthContext ctx) {
814 validate();
815 return values;
816 }
817
818 /**
842 * style information to use for a given state requires a single integer
843 * bit string where each bit in the integer represents a different state
844 * that the component is in. This method uses the componentState as
845 * reported in the SynthContext, in addition to custom states, to determine
846 * what this extended state is.</p>
847 *
848 * <p>In addition, this method checks the component in the given context
849 * for a client property called "Nimbus.State". If one exists, then it will
850 * decompose the String associated with that property to determine what
851 * state to return. In this way, the developer can force a component to be
852 * in a specific state, regardless of what the "real" state of the component
853 * is.</p>
854 *
855 * <p>The string associated with "Nimbus.State" would be of the form:
856 * <pre>Enabled+CustomState+MouseOver</pre></p>
857 *
858 * @param ctx
859 * @param v
860 * @return
861 */
862 @SuppressWarnings({"unchecked", "rawtypes"})
863 private int getExtendedState(SynthContext ctx, Values v) {
864 JComponent c = ctx.getComponent();
865 int xstate = 0;
866 int mask = 1;
867 //check for the Nimbus.State client property
868 //Performance NOTE: getClientProperty ends up inside a synchronized
869 //block, so there is some potential for performance issues here, however
870 //I'm not certain that there is one on a modern VM.
871 Object property = c.getClientProperty("Nimbus.State");
872 if (property != null) {
873 String stateNames = property.toString();
874 String[] states = stateNames.split("\\+");
875 if (v.stateTypes == null){
876 // standard states only
877 for (String stateStr : states) {
878 State.StandardState s = State.getStandardState(stateStr);
879 if (s != null) xstate |= s.getState();
880 }
881 } else {
882 // custom states
883 for (State<?> s : v.stateTypes) {
884 if (contains(states, s.getName())) {
885 xstate |= mask;
886 }
887 mask <<= 1;
888 }
889 }
890 } else {
891 //if there are no custom states defined, then simply return the
892 //state that Synth reported
893 if (v.stateTypes == null) return ctx.getComponentState();
894
895 //there are custom states on this values, so I'll have to iterate
896 //over them all and return a custom extended state
897 int state = ctx.getComponentState();
898 for (State s : v.stateTypes) {
899 if (s.isInState(c, state)) {
900 xstate |= mask;
901 }
902 mask <<= 1;
903 }
1010 return states[bestIndex];
1011 }
1012 if (wildIndex != -1) {
1013 lastState[0] = wildIndex;
1014 return states[wildIndex];
1015 }
1016 }
1017 lastState[0] = -1;
1018 return null;
1019 }
1020
1021 /**
1022 * Contains values such as the UIDefaults and painters associated with
1023 * a state. Whereas <code>State</code> represents a distinct state that a
1024 * component can be in (such as Enabled), this class represents the colors,
1025 * fonts, painters, etc associated with some state for this
1026 * style.
1027 */
1028 private final class RuntimeState implements Cloneable {
1029 int state;
1030 Painter<Object> backgroundPainter;
1031 Painter<Object> foregroundPainter;
1032 Painter<Object> borderPainter;
1033 String stateName;
1034 UIDefaults defaults = new UIDefaults(10, .7f);
1035
1036 private RuntimeState(int state, String stateName) {
1037 this.state = state;
1038 this.stateName = stateName;
1039 }
1040
1041 @Override
1042 public String toString() {
1043 return stateName;
1044 }
1045
1046 @Override
1047 public RuntimeState clone() {
1048 RuntimeState clone = new RuntimeState(state, stateName);
1049 clone.backgroundPainter = backgroundPainter;
1050 clone.foregroundPainter = foregroundPainter;
1051 clone.borderPainter = borderPainter;
1052 clone.defaults.putAll(defaults);
1053 return clone;
1054 }
1055 }
1056
1057 /**
1058 * Essentially a struct of data for a style. A default instance of this
1059 * class is used by NimbusStyle. Additional instances exist for each
1060 * component that has overrides.
1061 */
1062 private static final class Values {
1063 /**
1064 * The list of State types. A State represents a type of state, such
1065 * as Enabled, Default, WindowFocused, etc. These can be custom states.
1066 */
1067 State<?>[] stateTypes = null;
1068 /**
1069 * The list of actual runtime state representations. These can represent things such
1070 * as Enabled + Focused. Thus, they differ from States in that they contain
1071 * several states together, and have associated properties, data, etc.
1072 */
1073 RuntimeState[] states = null;
1074 /**
1075 * The content margins for this region.
1076 */
1077 Insets contentMargins;
1078 /**
1079 * Defaults on the region/component level.
1080 */
1081 UIDefaults defaults = new UIDefaults(10, .7f);
1082 /**
1083 * Simple cache. After a value has been looked up, it is stored
1084 * in this cache for later retrieval. The key is a concatenation of
1085 * the property being looked up, two dollar signs, and the extended
1086 * state. So for example:
1087 *
|