/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-15 The Processing Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package processing.mode.java.tweak;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import processing.mode.java.pdex.JavaTextAreaPainter;
public class ColorControlBox {
public boolean visible;
ArrayList<Handle> handles;
ColorMode colorMode;
Color color;
boolean ilegalColor = false;
boolean isBW;
boolean isHex;
String drawContext;
// interface
int x, y, width, height;
JavaTextAreaPainter painter;
public ColorControlBox(String context, ColorMode mode,
ArrayList<Handle> handles) {
this.drawContext = context;
this.colorMode = mode;
this.handles = handles;
// add this box to the handles so they can update this color on change
for (Handle h : handles) {
h.setColorBox(this);
}
isBW = isGrayScale();
isHex = isHexColor();
color = getCurrentColor();
visible = Settings.alwaysShowColorBoxes;
}
public void initInterface(JavaTextAreaPainter textAreaPainter,
int x, int y, int w, int h) {
this.painter = textAreaPainter;
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
public void setPos(int x, int y) {
this.x = x;
this.y = y;
}
public void draw(Graphics2D g2d) {
if (!visible) {
return;
}
AffineTransform trans = g2d.getTransform();
g2d.translate(x, y);
// draw current color
g2d.setColor(color);
g2d.fillRoundRect(0, 0, width, height, 5, 5);
// draw black outline
g2d.setStroke(new BasicStroke(1));
g2d.setColor(Color.BLACK);
g2d.drawRoundRect(0, 0, width, height, 5, 5);
if (ilegalColor) {
g2d.setColor(Color.RED);
g2d.setStroke(new BasicStroke(2));
g2d.drawLine(width-3, 3, 3, height-3);
}
g2d.setTransform(trans);
}
public boolean isGrayScale() {
if (handles.size() <= 2) {
int value = handles.get(0).newValue.intValue();
if ((value&0xff000000) == 0) {
return true;
}
}
return false;
}
/**
* @return true if number is hex or webcolor
*/
private boolean isHexColor() {
if (handles.get(0).type == "hex" || handles.get(0).type == "webcolor") {
int value = handles.get(0).value.intValue();
if ((value & 0xff000000) != 0) {
return true;
}
}
return false;
}
public Color getCurrentColor()
{
try {
if (handles.size() == 1)
{
if (isBW) {
// treat as color(gray)
float gray = handles.get(0).newValue.floatValue();
return verifiedGrayColor(gray);
}
else {
// treat as color(argb)
int argb = handles.get(0).newValue.intValue();
return verifiedHexColor(argb);
}
}
else if (handles.size() == 2)
{
if (isBW) {
// color(gray, alpha)
float gray = handles.get(0).newValue.floatValue();
return verifiedGrayColor(gray);
}
else {
// treat as color(argb, a)
int argb = handles.get(0).newValue.intValue();
float a = handles.get(1).newValue.floatValue();
return verifiedHexColor(argb, a);
}
}
else if (handles.size() == 3)
{
// color(v1, v2, v3)
float v1 = handles.get(0).newValue.floatValue();
float v2 = handles.get(1).newValue.floatValue();
float v3 = handles.get(2).newValue.floatValue();
if (colorMode.modeType == ColorMode.RGB) {
return verifiedRGBColor(v1, v2, v3, colorMode.aMax);
}
else {
return verifiedHSBColor(v1, v2, v3, colorMode.aMax);
}
}
else if (handles.size() == 4)
{
// color(v1, v2, v3, alpha)
float v1 = handles.get(0).newValue.floatValue();
float v2 = handles.get(1).newValue.floatValue();
float v3 = handles.get(2).newValue.floatValue();
float a = handles.get(3).newValue.floatValue();
if (colorMode.modeType == ColorMode.RGB) {
return verifiedRGBColor(v1, v2, v3, a);
}
else {
return verifiedHSBColor(v1, v2, v3, a);
}
}
}
catch (Exception e) {
System.out.println("error parsing color value: " + e.toString());
ilegalColor = true;
return Color.WHITE;
}
// couldn't figure out this color, return WHITE color
ilegalColor = true;
return Color.WHITE;
}
private Color verifiedGrayColor(float gray)
{
if (gray < 0 || gray > colorMode.v1Max) {
return colorError();
}
ilegalColor = false;
gray = gray/colorMode.v1Max * 255;
return new Color((int)gray, (int)gray, (int)gray, 255);
}
private Color verifiedHexColor(int argb)
{
int r = (argb>>16)&0xff;
int g = (argb>>8)&0xff;
int b = (argb&0xff);
ilegalColor = false;
return new Color(r, g, b, 255);
}
private Color verifiedHexColor(int argb, float alpha)
{
int r = (argb>>16)&0xff;
int g = (argb>>8)&0xff;
int b = (argb&0xff);
ilegalColor = false;
return new Color(r, g, b, 255);
}
public Color verifiedRGBColor(float r, float g, float b, float a)
{
if (r < 0 || r > colorMode.v1Max ||
g < 0 || g > colorMode.v2Max ||
b < 0 || b > colorMode.v3Max) {
return colorError();
}
ilegalColor = false;
r = r/colorMode.v1Max * 255;
g = g/colorMode.v2Max * 255;
b = b/colorMode.v3Max * 255;
return new Color((int)r, (int)g, (int)b, 255);
}
public Color verifiedHSBColor(float h, float s, float b, float a)
{
if (h < 0 || h > colorMode.v1Max ||
s < 0 || s > colorMode.v2Max ||
b < 0 || b > colorMode.v3Max) {
return colorError();
}
ilegalColor = false;
Color c = Color.getHSBColor(h/colorMode.v1Max, s/colorMode.v2Max, b/colorMode.v3Max);
return new Color(c.getRed(), c.getGreen(), c.getBlue(), 255);
}
private Color colorError()
{
ilegalColor = true;
return Color.WHITE;
}
public void colorChanged()
{
color = getCurrentColor();
}
public int getTabIndex()
{
return handles.get(0).tabIndex;
}
public int getLine()
{
return handles.get(0).line;
}
public int getCharIndex()
{
int lastHandle = handles.size()-1;
return handles.get(lastHandle).newEndChar + 2;
}
/* Check if the point is in the box
*
*/
public boolean pick(int mx, int my)
{
if (!visible) {
return false;
}
if (mx>x && mx < x+width && my>y && my<y+height) {
return true;
}
return false;
}
/* Only show the color box if mouse is on the same line
*
* return true if there was change
*/
public boolean setMouseY(int my)
{
boolean change = false;
if (my>y && my<y+height) {
if (!visible) {
change = true;
}
visible = true;
}
else {
if (visible) {
change = true;
}
visible = false;
}
return change;
}
/* Update the color numbers with the new values that were selected
* in the color selector
*
* hue, saturation and brightness parameters are always 0-255
*/
public void selectorChanged(int hue, int saturation, int brightness)
{
if (isBW) {
// color(gray) or color(gray, alpha)
handles.get(0).setValue((float)hue/255*colorMode.v1Max);
}
else {
if (handles.size() == 1 || handles.size() == 2) {
// color(argb)
int prevVal = handles.get(0).newValue.intValue();
int prevAlpha = (prevVal>>24)&0xff;
Color c = Color.getHSBColor((float)hue/255, (float)saturation/255, (float)brightness/255);
int newVal = (prevAlpha<<24) | (c.getRed()<<16) | (c.getGreen()<<8) | (c.getBlue());
handles.get(0).setValue(newVal);
}
else if (handles.size() == 3 || handles.size() == 4) {
// color(v1, v2, v3) or color(v1, v2, v3, alpha)
if (colorMode.modeType == ColorMode.HSB) {
// HSB
float v1 = (float)hue/255 * colorMode.v1Max;
float v2 = (float)saturation/255 * colorMode.v2Max;
float v3 = (float)brightness/255 * colorMode.v3Max;
handles.get(0).setValue(v1);
handles.get(1).setValue(v2);
handles.get(2).setValue(v3);
}
else {
// RGB
Color c = Color.getHSBColor((float)hue/255, (float)saturation/255, (float)brightness/255);
handles.get(0).setValue((float)c.getRed()/255*colorMode.v1Max);
handles.get(1).setValue((float)c.getGreen()/255*colorMode.v2Max);
handles.get(2).setValue((float)c.getBlue()/255*colorMode.v3Max);
}
}
}
// update our own color
color = getCurrentColor();
// update code text painter so the user will see the changes
painter.updateCodeText();
painter.repaint();
}
public String toString() {
return handles.size() + " handles, color mode: " + colorMode.toString();
}
}