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