/* * Copyright 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.example.spline.model; import android.databinding.BaseObservable; import android.databinding.Bindable; import com.android.databinding.library.baseAdapters.BR; /** * Data model class that wraps a standard Android color int with observable Hue, Saturation, Value, * Red, Green and Blue fields. The HSV and color fields are updated whenever there is a change in * RGB values and vice-versa. */ public class Color extends BaseObservable { private int color; private float hue; private float saturation; private float value; private int red; private int blue; private int green; private int alpha; public Color() { alpha = 255; } public Color(int color) { this.color = color; updateValues(); } public Color(Color color) { if (color != null) { this.color = color.getColor(); } updateValues(); } public void updateValues() { updateValues(true); } public void updateValues(boolean updateHSV) { if (updateHSV) { float[] hsv = new float[3]; android.graphics.Color.colorToHSV(this.color, hsv); this.hue = hsv[0]; this.saturation = hsv[1]; this.value = hsv[2]; } int oldRgbColor = android.graphics.Color.argb(this.alpha, this.red, this.green, this.blue); float[] oldRgbHsv = new float[3]; android.graphics.Color.colorToHSV(oldRgbColor, oldRgbHsv); if (this.hue != oldRgbHsv[0] || this.saturation != oldRgbHsv[1] || this.value != oldRgbHsv[2]) { this.red = android.graphics.Color.red(this.color); this.green = android.graphics.Color.green(this.color); this.blue = android.graphics.Color.blue(this.color); this.alpha = android.graphics.Color.alpha(this.color); } } public int getColor() { return this.color; } public void setColor(int color) { this.color = color; updateValues(); notifyChange(); } /** * The following getters and setters with String in the name are a work around for 2-way data * binding of these integer properties to the text attribute of EditText fields. As of Android * Studio 2.3, should now use the InverseMethod annotation on standalone converter classes * inverse conversion method to achieve this type conversion. These were maintained here because * the circular dependencies of color properties on each other make the double bind calls * necessitated by the converter classes causes a drift in color properties as one of the * properties is adjusted. * * @return a String to be used for 2-way binding */ public String getHexString() { String s = Integer.toHexString(getColor()); if (s.length() >= 2) { return "#" + s.substring(2); } else { return "#000000"; } } public void setHexString(String hexString) { if (!getHexString().equals(hexString)) { // Only accept a string as a valid color if it contains 6 digits and '#' if (hexString.length() == 7) { int color = android.graphics.Color.parseColor(hexString); setColor(color); } } } public String getRedString() { return Integer.toString(this.red); } public void setRedString(String redString) { try { int r = Integer.parseInt(redString); if (r != getRed()) { setRed(r); } } catch (NumberFormatException e) { // Don't do anything for now } } public String getGreenString() { return Integer.toString(this.green); } public void setGreenString(String greenString) { try { int g = Integer.parseInt(greenString); if (g != getGreen()) { setGreen(g); } } catch (NumberFormatException e) { // Don't do anything for now } } public String getBlueString() { return Integer.toString(this.blue); } public void setBlueString(String blueString) { try { int b = Integer.parseInt(blueString); if (b != getBlue()) { setBlue(b); } } catch (NumberFormatException e) { // Don't do anything for now } } @Bindable public float getHue() { return this.hue; } public void setHue(float hue) { float[] hsv = {hue, this.saturation, this.value}; this.color = android.graphics.Color.HSVToColor(this.alpha, hsv); updateValues(false); this.hue = Math.min(Math.max(0f, hue), 359.9f); // For each HSV and RGB property, a change in the property changes both the property itself // and the resultant color notifyPropertyChanged(BR.hue); notifyPropertyChanged(BR.color); } @Bindable public float getSaturation() { return this.saturation; } public void setSaturation(float saturation) { float[] hsv = {this.hue, saturation, this.value}; this.color = android.graphics.Color.HSVToColor(this.alpha, hsv); updateValues(false); // Clamp the saturation value this.saturation = Math.min(Math.max(0f, saturation), 1.0f); notifyPropertyChanged(BR.saturation); notifyPropertyChanged(BR.color); } @Bindable public float getValue() { return this.value; } public void setValue(float value) { float[] hsv = {this.hue, this.saturation, value}; this.color = android.graphics.Color.HSVToColor(this.alpha, hsv); updateValues(false); // Clamp the value this.value = Math.min(Math.max(0f, value), 1.0f); notifyPropertyChanged(BR.value); notifyPropertyChanged(BR.color); } public int getRed() { return this.red; } public void setRed(int red) { this.color = android.graphics.Color.argb(this.alpha, red, this.green, this.blue); updateValues(); // Setting red will modify HSV and color properties, so notifyingChange is simpler syntax // than calling notifyPropertyChanged on five different Binding Resources notifyChange(); } public int getGreen() { return this.green; } public void setGreen(int green) { this.color = android.graphics.Color.argb(this.alpha, this.red, green, this.blue); updateValues(); notifyChange(); } public int getBlue() { return this.blue; } public void setBlue(int blue) { this.color = android.graphics.Color.argb(this.alpha, this.red, this.green, blue); updateValues(); notifyChange(); } @Bindable public int getAlpha() { return this.alpha; } public void setAlpha(int alpha) { this.color = android.graphics.Color.argb(alpha, this.red, this.green, this.blue); updateValues(); notifyPropertyChanged(BR.alpha); } }