1 /*
   2  * Copyright (c) 2005, 2006, 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 class DerivedColor extends Color {
  42     private final String uiDefaultParentName;
  43     private final float hOffset, sOffset, bOffset;
  44     private final int aOffset;
  45     private int argbValue;
  46 
  47     DerivedColor(String uiDefaultParentName, float hOffset, float sOffset, float bOffset, int aOffset) {
  48         super(0);
  49         this.uiDefaultParentName = uiDefaultParentName;
  50         this.hOffset = hOffset;
  51         this.sOffset = sOffset;
  52         this.bOffset = bOffset;
  53         this.aOffset = aOffset;
  54     }
  55 
  56     public String getUiDefaultParentName() {
  57         return uiDefaultParentName;
  58     }
  59 
  60     public float getHueOffset() {
  61         return hOffset;
  62     }
  63 
  64     public float getSaturationOffset() {
  65         return sOffset;
  66     }
  67 
  68     public float getBrightnessOffset() {
  69         return bOffset;
  70     }
  71 
  72     public int getAlphaOffset() {
  73         return aOffset;
  74     }
  75 
  76     /**
  77      * Recalculate the derived color from the UIManager parent color and offsets
  78      */
  79     public void rederiveColor() {
  80         Color src = UIManager.getColor(uiDefaultParentName);
  81         if (src != null) {
  82             float[] tmp = Color.RGBtoHSB(src.getRed(), src.getGreen(), src.getBlue(), null);
  83             // apply offsets
  84             tmp[0] = clamp(tmp[0] + hOffset);
  85             tmp[1] = clamp(tmp[1] + sOffset);
  86             tmp[2] = clamp(tmp[2] + bOffset);
  87             int alpha = clamp(src.getAlpha() + aOffset);
  88             argbValue = (Color.HSBtoRGB(tmp[0], tmp[1], tmp[2]) & 0xFFFFFF) | (alpha << 24);
  89         } else {
  90             float[] tmp = new float[3];
  91             tmp[0] = clamp(hOffset);
  92             tmp[1] = clamp(sOffset);
  93             tmp[2] = clamp(bOffset);
  94             int alpha = clamp(aOffset);
  95             argbValue = (Color.HSBtoRGB(tmp[0], tmp[1], tmp[2]) & 0xFFFFFF) | (alpha << 24);
  96         }
  97     }
  98 
  99     /**
 100      * Returns the RGB value representing the color in the default sRGB {@link java.awt.image.ColorModel}. (Bits 24-31
 101      * are alpha, 16-23 are red, 8-15 are green, 0-7 are blue).
 102      *
 103      * @return the RGB value of the color in the default sRGB <code>ColorModel</code>.
 104      * @see java.awt.image.ColorModel#getRGBdefault
 105      * @see #getRed
 106      * @see #getGreen
 107      * @see #getBlue
 108      * @since JDK1.0
 109      */
 110     @Override public int getRGB() {
 111         return argbValue;
 112     }
 113 
 114     @Override
 115     public boolean equals(Object o) {
 116         if (this == o) return true;
 117         if (!(o instanceof DerivedColor)) return false;
 118         DerivedColor that = (DerivedColor) o;
 119         if (aOffset != that.aOffset) return false;
 120         if (Float.compare(that.bOffset, bOffset) != 0) return false;
 121         if (Float.compare(that.hOffset, hOffset) != 0) return false;
 122         if (Float.compare(that.sOffset, sOffset) != 0) return false;
 123         if (!uiDefaultParentName.equals(that.uiDefaultParentName)) return false;
 124         return true;
 125     }
 126 
 127     @Override
 128     public int hashCode() {
 129         int result = uiDefaultParentName.hashCode();
 130         result = 31 * result + hOffset != +0.0f ?
 131                 Float.floatToIntBits(hOffset) : 0;
 132         result = 31 * result + sOffset != +0.0f ?
 133                 Float.floatToIntBits(sOffset) : 0;
 134         result = 31 * result + bOffset != +0.0f ?
 135                 Float.floatToIntBits(bOffset) : 0;
 136         result = 31 * result + aOffset;
 137         return result;
 138     }
 139 
 140     private float clamp(float value) {
 141         if (value < 0) {
 142             value = 0;
 143         } else if (value > 1) {
 144             value = 1;
 145         }
 146         return value;
 147     }
 148 
 149     private int clamp(int value) {
 150         if (value < 0) {
 151             value = 0;
 152         } else if (value > 255) {
 153             value = 255;
 154         }
 155         return value;
 156     }
 157 
 158     /**
 159      * Returns a string representation of this <code>Color</code>. This method
 160      * is intended to be used only for debugging purposes. The content and
 161      * format of the returned string might vary between implementations. The
 162      * returned string might be empty but cannot be <code>null</code>.
 163      *
 164      * @return a String representation of this <code>Color</code>.
 165      */
 166     @Override
 167     public String toString() {
 168         Color src = UIManager.getColor(uiDefaultParentName);
 169         String s = "DerivedColor(color=" + getRed() + "," + getGreen() + "," + getBlue() +
 170                 " parent=" + uiDefaultParentName +
 171                 " offsets=" + getHueOffset() + "," + getSaturationOffset() + ","
 172                 + getBrightnessOffset() + "," + getAlphaOffset();
 173         return src == null ? s : s + " pColor=" + src.getRed() + "," + src.getGreen() + "," + src.getBlue();
 174     }
 175 
 176     static class UIResource extends DerivedColor implements javax.swing.plaf.UIResource {
 177         UIResource(String uiDefaultParentName, float hOffset, float sOffset,
 178                    float bOffset, int aOffset) {
 179             super(uiDefaultParentName, hOffset, sOffset, bOffset, aOffset);
 180         }
 181 
 182         @Override
 183         public boolean equals(Object o) {
 184             return (o instanceof UIResource) && super.equals(o);
 185         }
 186 
 187         @Override
 188         public int hashCode() {
 189             return super.hashCode() + 7;
 190         }
 191     }
 192 }