Plotter
This commit is contained in:
405
app/src/main/java/uz/shift/colorpicker/LineColorPicker.java
Normal file
405
app/src/main/java/uz/shift/colorpicker/LineColorPicker.java
Normal file
@@ -0,0 +1,405 @@
|
||||
package uz.shift.colorpicker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import org.solovyev.android.calculator.R;
|
||||
|
||||
|
||||
public class LineColorPicker extends View {
|
||||
|
||||
public static final int HORIZONTAL = 0;
|
||||
public static final int VERTICAL = 1;
|
||||
|
||||
int[] colors = isInEditMode() ? Palette.DEFAULT : new int[1];
|
||||
// indicate if nothing selected
|
||||
boolean isColorSelected = false;
|
||||
private Paint paint;
|
||||
private Rect rect = new Rect();
|
||||
private int selectedColor = colors[0];
|
||||
private OnColorChangedListener onColorChanged;
|
||||
private int cellSize;
|
||||
private int mOrientation = HORIZONTAL;
|
||||
private boolean isClick = false;
|
||||
private int screenW;
|
||||
private int screenH;
|
||||
|
||||
public LineColorPicker(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
paint = new Paint();
|
||||
paint.setStyle(Style.FILL);
|
||||
|
||||
final TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.LineColorPicker, 0, 0);
|
||||
|
||||
try {
|
||||
mOrientation = a.getInteger(R.styleable.LineColorPicker_lcp_orientation, HORIZONTAL);
|
||||
|
||||
if (!isInEditMode()) {
|
||||
final int colorsArrayResId = a.getResourceId(R.styleable.LineColorPicker_lcp_colors, -1);
|
||||
|
||||
if (colorsArrayResId > 0) {
|
||||
final int[] colors = context.getResources().getIntArray(colorsArrayResId);
|
||||
setColors(colors);
|
||||
}
|
||||
}
|
||||
|
||||
final int selected = a.getInteger(R.styleable.LineColorPicker_lcp_selectedColorIndex, -1);
|
||||
|
||||
if (selected != -1) {
|
||||
final int[] currentColors = getColors();
|
||||
|
||||
final int currentColorsLength = currentColors != null ? currentColors.length : 0;
|
||||
|
||||
if (selected < currentColorsLength) {
|
||||
setSelectedColorPosition(selected);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (mOrientation == HORIZONTAL) {
|
||||
drawHorizontalPicker(canvas);
|
||||
} else {
|
||||
drawVerticalPicker(canvas);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void drawVerticalPicker(Canvas canvas) {
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = getWidth();
|
||||
rect.bottom = 0;
|
||||
|
||||
// 8%
|
||||
int margin = Math.round(getWidth() * 0.08f);
|
||||
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
|
||||
paint.setColor(colors[i]);
|
||||
|
||||
rect.top = rect.bottom;
|
||||
rect.bottom += cellSize;
|
||||
|
||||
if (isColorSelected && colors[i] == selectedColor) {
|
||||
rect.left = 0;
|
||||
rect.right = getWidth();
|
||||
} else {
|
||||
rect.left = margin;
|
||||
rect.right = getWidth() - margin;
|
||||
}
|
||||
|
||||
canvas.drawRect(rect, paint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void drawHorizontalPicker(Canvas canvas) {
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = 0;
|
||||
rect.bottom = getHeight();
|
||||
|
||||
// 8%
|
||||
int margin = Math.round(getHeight() * 0.08f);
|
||||
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
|
||||
paint.setColor(colors[i]);
|
||||
|
||||
rect.left = rect.right;
|
||||
rect.right += cellSize;
|
||||
|
||||
if (isColorSelected && colors[i] == selectedColor) {
|
||||
rect.top = 0;
|
||||
rect.bottom = getHeight();
|
||||
} else {
|
||||
rect.top = margin;
|
||||
rect.bottom = getHeight() - margin;
|
||||
}
|
||||
|
||||
canvas.drawRect(rect, paint);
|
||||
}
|
||||
}
|
||||
|
||||
private void onColorChanged(int color) {
|
||||
if (onColorChanged != null) {
|
||||
onColorChanged.onColorChanged(color);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
|
||||
int actionId = event.getAction();
|
||||
|
||||
int newColor;
|
||||
|
||||
switch (actionId) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
isClick = true;
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
newColor = getColorAtXY(event.getX(), event.getY());
|
||||
|
||||
setSelectedColor(newColor);
|
||||
|
||||
if (isClick) {
|
||||
performClick();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
newColor = getColorAtXY(event.getX(), event.getY());
|
||||
|
||||
setSelectedColor(newColor);
|
||||
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
isClick = false;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_OUTSIDE:
|
||||
isClick = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return color at x,y coordinate of view.
|
||||
*/
|
||||
private int getColorAtXY(float x, float y) {
|
||||
|
||||
// FIXME: colors.length == 0 -> devision by ZERO.s
|
||||
|
||||
if (mOrientation == HORIZONTAL) {
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
left = right;
|
||||
right += cellSize;
|
||||
|
||||
if (left <= x && right >= x) {
|
||||
return colors[i];
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
int top = 0;
|
||||
int bottom = 0;
|
||||
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
top = bottom;
|
||||
bottom += cellSize;
|
||||
|
||||
if (y >= top && y <= bottom) {
|
||||
return colors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
// begin boilerplate code that allows parent classes to save state
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
|
||||
SavedState ss = new SavedState(superState);
|
||||
// end
|
||||
|
||||
ss.selectedColor = this.selectedColor;
|
||||
ss.isColorSelected = this.isColorSelected;
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
// begin boilerplate code so parent classes can restore state
|
||||
if (!(state instanceof SavedState)) {
|
||||
super.onRestoreInstanceState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
SavedState ss = (SavedState) state;
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
// end
|
||||
|
||||
this.selectedColor = ss.selectedColor;
|
||||
this.isColorSelected = ss.isColorSelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performClick() {
|
||||
return super.performClick();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
|
||||
screenW = w;
|
||||
screenH = h;
|
||||
|
||||
recalcCellSize();
|
||||
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return currently selected color.
|
||||
*/
|
||||
public int getColor() {
|
||||
return selectedColor;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
// int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
// this.setMeasuredDimension(parentWidth, parentHeight);
|
||||
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Set selected color as color value from palette.
|
||||
*/
|
||||
public void setSelectedColor(int color) {
|
||||
|
||||
// not from current palette
|
||||
if (!containsColor(colors, color)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do we need to re-draw view?
|
||||
if (!isColorSelected || selectedColor != color) {
|
||||
this.selectedColor = color;
|
||||
|
||||
isColorSelected = true;
|
||||
|
||||
invalidate();
|
||||
|
||||
onColorChanged(color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set selected color as index from palete
|
||||
*/
|
||||
public void setSelectedColorPosition(int position) {
|
||||
setSelectedColor(colors[position]);
|
||||
}
|
||||
|
||||
private int recalcCellSize() {
|
||||
|
||||
if (mOrientation == HORIZONTAL) {
|
||||
cellSize = Math.round(screenW / (colors.length * 1f));
|
||||
} else {
|
||||
cellSize = Math.round(screenH / (colors.length * 1f));
|
||||
}
|
||||
|
||||
return cellSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current picker palete
|
||||
*/
|
||||
public int[] getColors() {
|
||||
return colors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set picker palette
|
||||
*/
|
||||
public void setColors(int[] colors) {
|
||||
// TODO: selected color can be NOT in set of colors
|
||||
// FIXME: colors can be null
|
||||
this.colors = colors;
|
||||
|
||||
if (!containsColor(colors, selectedColor)) {
|
||||
selectedColor = colors[0];
|
||||
}
|
||||
|
||||
recalcCellSize();
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if palette contains this color
|
||||
*/
|
||||
private boolean containsColor(int[] colors, int c) {
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
if (colors[i] == c)
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set onColorChanged listener
|
||||
*
|
||||
* @param l
|
||||
*/
|
||||
public void setOnColorChangedListener(OnColorChangedListener l) {
|
||||
this.onColorChanged = l;
|
||||
}
|
||||
|
||||
static class SavedState extends BaseSavedState {
|
||||
// required field that makes Parcelables from a Parcel
|
||||
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
int selectedColor;
|
||||
boolean isColorSelected;
|
||||
|
||||
SavedState(Parcelable superState) {
|
||||
super(superState);
|
||||
}
|
||||
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
this.selectedColor = in.readInt();
|
||||
this.isColorSelected = in.readInt() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeInt(this.selectedColor);
|
||||
out.writeInt(this.isColorSelected ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package uz.shift.colorpicker;
|
||||
|
||||
public interface OnColorChangedListener {
|
||||
void onColorChanged(int c);
|
||||
}
|
24
app/src/main/java/uz/shift/colorpicker/Palette.java
Normal file
24
app/src/main/java/uz/shift/colorpicker/Palette.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package uz.shift.colorpicker;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
public class Palette {
|
||||
|
||||
public static int[] DEFAULT;
|
||||
|
||||
static {
|
||||
|
||||
DEFAULT = new int[]{Color.parseColor("#b8c847"),
|
||||
Color.parseColor("#67bb43"), Color.parseColor("#41b691"),
|
||||
Color.parseColor("#4182b6"), Color.parseColor("#4149b6"),
|
||||
Color.parseColor("#7641b6"), Color.parseColor("#b741a7"),
|
||||
Color.parseColor("#c54657"), Color.parseColor("#d1694a"),
|
||||
Color.parseColor("#d1904a"), Color.parseColor("#d1c54a")};
|
||||
|
||||
}
|
||||
|
||||
private Palette() {
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user