1 /*
   2  * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing.plaf.nimbus;
  26 
  27 import javax.swing.UIManager;
  28 import java.awt.Color;
  29 import java.beans.PropertyChangeSupport;
  30 import java.beans.PropertyChangeListener;
  31 
  32 /**
  33  * DerivedColor - A color implementation that is derived from a UIManager
  34  * defaults table color and a set of offsets. It can be rederived at any point
  35  * by calling rederiveColor(). For example when its parent color changes and it
  36  * value will update to reflect the new derived color. Property change events
  37  * are fired for the "rgb" property when the derived color changes.
  38  *
  39  * @author Jasper Potts
  40  */
  41 @SuppressWarnings("serial") // Same-version serialization only
  42 class DerivedColor extends Color {
  43     private final String uiDefaultParentName;
  44     private final float hOffset, sOffset, bOffset;
  45     private final int aOffset;
  46     private int argbValue;
  47 
  48     DerivedColor(String uiDefaultParentName, float hOffset, float sOffset, float bOffset, int aOffset) {
  49         super(0);
  50         this.uiDefaultParentName = uiDefaultParentName;
  51         this.hOffset = hOffset;
  52         this.sOffset = sOffset;
  53         this.bOffset = bOffset;
  54         this.aOffset = aOffset;
  55     }
  56 
  57     public String getUiDefaultParentName() {
  58         return uiDefaultParentName;
  59     }
  60 
  61     public float getHueOffset() {
  62         return hOffset;
  63     }
  64 
  65     public float getSaturationOffset() {
  66         return sOffset;
  67     }
  68 
  69     public float getBrightnessOffset() {
  70         return bOffset;
  71     }
  72 
  73     public int getAlphaOffset() {
  74         return aOffset;
  75     }
  76 
  77     /**
  78      * Recalculate the derived color from the UIManager parent color and offsets
  79      */
  80     public void rederiveColor() {
  81         Color src = UIManager.getColor(uiDefaultParentName);
  82         if (src != null) {
  83             float[] tmp = Color.RGBtoHSB(src.getRed(), src.getGreen(), src.getBlue(), null);
  84             // apply offsets
  85             tmp[0] = clamp(tmp[0] + hOffset);
  86             tmp[1] = clamp(tmp[1] + sOffset);
  87             tmp[2] = clamp(tmp[2] + bOffset);
  88             int alpha = clamp(src.getAlpha() + aOffset);
  89             argbValue = (Color.HSBtoRGB(tmp[0], tmp[1], tmp[2]) & 0xFFFFFF) | (alpha << 24);
  90         } else {
  91             float[] tmp = new float[3];
  92             tmp[0] = clamp(hOffset);
  93             tmp[1] = clamp(sOffset);
  94             tmp[2] = clamp(bOffset);
  95             int alpha = clamp(aOffset);
  96             argbValue = (Color.HSBtoRGB(tmp[0], tmp[1], tmp[2]) & 0xFFFFFF) | (alpha << 24);
  97         }
  98     }
  99 
 100     /**
 101      * Returns the RGB value representing the color in the default sRGB {@link java.awt.image.ColorModel}. (Bits 24-31
 102      * are alpha, 16-23 are red, 8-15 are green, 0-7 are blue).
 103      *
 104      * @return the RGB value of the color in the default sRGB <code>ColorModel</code>.
 105      * @see java.awt.image.ColorModel#getRGBdefault
 106      * @see #getRed
 107      * @see #getGreen
 108      * @see #getBlue
 109      * @since JDK1.0
 110      */
 111     @Override public int getRGB() {
 112         return argbValue;
 113     }
 114 
 115     @Override
 116     public boolean equals(Object o) {
 117         if (this == o) return true;
 118         if (!(o instanceof DerivedColor)) return false;
 119         DerivedColor that = (DerivedColor) o;
 120         if (aOffset != that.aOffset) return false;
 121         if (Float.compare(that.bOffset, bOffset) != 0) return false;
 122         if (Float.compare(that.hOffset, hOffset) != 0) return false;
 123         if (Float.compare(that.sOffset, sOffset) != 0) return false;
 124         if (!uiDefaultParentName.equals(that.uiDefaultParentName)) return false;
 125         return true;
 126     }
 127 
 128     @Override
 129     public int hashCode() {
 130         int result = uiDefaultParentName.hashCode();
 131         result = 31 * result + hOffset != +0.0f ?
 132                 Float.floatToIntBits(hOffset) : 0;
 133         result = 31 * result + sOffset != +0.0f ?
 134                 Float.floatToIntBits(sOffset) : 0;
 135         result = 31 * result + bOffset != +0.0f ?
 136                 Float.floatToIntBits(bOffset) : 0;
 137         result = 31 * result + aOffset;
 138         return result;
 139     }
 140 
 141     private float clamp(float value) {
 142         if (value < 0) {
 143             value = 0;
 144         } else if (value > 1) {
 145             value = 1;
 146         }
 147         return value;
 148     }
 149 
 150     private int clamp(int value) {
 151         if (value < 0) {
 152             value = 0;
 153         } else if (value > 255) {
 154             value = 255;
 155         }
 156         return value;
 157     }
 158 
 159     /**
 160      * Returns a string representation of this <code>Color</code>. This method
 161      * is intended to be used only for debugging purposes. The content and
 162      * format of the returned string might vary between implementations. The
 163      * returned string might be empty but cannot be <code>null</code>.
 164      *
 165      * @return a String representation of this <code>Color</code>.
 166      */
 167     @Override
 168     public String toString() {
 169         Color src = UIManager.getColor(uiDefaultParentName);
 170         String s = "DerivedColor(color=" + getRed() + "," + getGreen() + "," + getBlue() +
 171                 " parent=" + uiDefaultParentName +
 172                 " offsets=" + getHueOffset() + "," + getSaturationOffset() + ","
 173                 + getBrightnessOffset() + "," + getAlphaOffset();
 174         return src == null ? s : s + " pColor=" + src.getRed() + "," + src.getGreen() + "," + src.getBlue();
 175     }
 176 
 177     @SuppressWarnings("serial") // Same-version serialization only
 178     static class UIResource extends DerivedColor implements javax.swing.plaf.UIResource {
 179         UIResource(String uiDefaultParentName, float hOffset, float sOffset,
 180                    float bOffset, int aOffset) {
 181             super(uiDefaultParentName, hOffset, sOffset, bOffset, aOffset);
 182         }
 183 
 184         @Override
 185         public boolean equals(Object o) {
 186             return (o instanceof UIResource) && super.equals(o);
 187         }
 188 
 189         @Override
 190         public int hashCode() {
 191             return super.hashCode() + 7;
 192         }
 193     }
 194 }