package yuku.ambilwarna;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.afollestad.materialdialogs.MaterialDialog;
public class AmbilWarnaDialog {
public interface OnAmbilWarnaListener {
void onCancel(AmbilWarnaDialog dialog);
void onOk(AmbilWarnaDialog dialog, int color);
}
final MaterialDialog dialog;
private final boolean supportsAlpha;
final OnAmbilWarnaListener listener;
final View viewHue;
final AmbilWarnaSquare viewSatVal;
final ImageView viewCursor;
final ImageView viewAlphaCursor;
final View viewOldColor;
final View viewNewColor;
final View viewAlphaOverlay;
final ImageView viewTarget;
final ImageView viewAlphaCheckered;
final ViewGroup viewContainer;
final float[] currentColorHsv = new float[3];
int alpha;
/**
* Create an AmbilWarnaDialog.
*
* @param context activity context
* @param color current color
* @param listener an OnAmbilWarnaListener, allowing you to get back error or OK
*/
public AmbilWarnaDialog(final Context context, int color, OnAmbilWarnaListener listener) {
this(context, color, false, listener);
}
/**
* Create an AmbilWarnaDialog.
*
* @param context activity context
* @param color current color
* @param supportsAlpha whether alpha/transparency controls are enabled
* @param listener an OnAmbilWarnaListener, allowing you to get back error or OK
*/
public AmbilWarnaDialog(final Context context, int color, boolean supportsAlpha, OnAmbilWarnaListener listener) {
this.supportsAlpha = supportsAlpha;
this.listener = listener;
if (!supportsAlpha) { // remove alpha if not supported
color = color | 0xff000000;
}
Color.colorToHSV(color, currentColorHsv);
alpha = Color.alpha(color);
dialog = new MaterialDialog.Builder(context)
.customView(R.layout.ambilwarna_dialog, false)
.positiveText(android.R.string.ok)
.negativeText(android.R.string.cancel)
.callback(new MaterialDialog.ButtonCallback() {
@Override
public void onPositive(final MaterialDialog dialog) {
if (AmbilWarnaDialog.this.listener != null) {
AmbilWarnaDialog.this.listener.onOk(AmbilWarnaDialog.this, getColor());
}
}
@Override
public void onNegative(final MaterialDialog dialog) {
if (AmbilWarnaDialog.this.listener != null) {
AmbilWarnaDialog.this.listener.onCancel(AmbilWarnaDialog.this);
}
}
})
.dismissListener(dialog -> {
if (AmbilWarnaDialog.this.listener != null) {
AmbilWarnaDialog.this.listener.onCancel(AmbilWarnaDialog.this);
}
})
.build();
final View view = dialog.getCustomView();
viewHue = view.findViewById(R.id.ambilwarna_viewHue);
viewSatVal = (AmbilWarnaSquare) view.findViewById(R.id.ambilwarna_viewSatBri);
viewCursor = (ImageView) view.findViewById(R.id.ambilwarna_cursor);
viewOldColor = view.findViewById(R.id.ambilwarna_oldColor);
viewNewColor = view.findViewById(R.id.ambilwarna_newColor);
viewTarget = (ImageView) view.findViewById(R.id.ambilwarna_target);
viewContainer = (ViewGroup) view.findViewById(R.id.ambilwarna_viewContainer);
viewAlphaOverlay = view.findViewById(R.id.ambilwarna_overlay);
viewAlphaCursor = (ImageView) view.findViewById(R.id.ambilwarna_alphaCursor);
viewAlphaCheckered = (ImageView) view.findViewById(R.id.ambilwarna_alphaCheckered);
{ // hide/show alpha
viewAlphaOverlay.setVisibility(supportsAlpha? View.VISIBLE: View.GONE);
viewAlphaCursor.setVisibility(supportsAlpha? View.VISIBLE: View.GONE);
viewAlphaCheckered.setVisibility(supportsAlpha? View.VISIBLE: View.GONE);
}
viewSatVal.setHue(getHue());
viewOldColor.setBackgroundColor(color);
viewNewColor.setBackgroundColor(color);
viewHue.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_MOVE
|| event.getAction() == MotionEvent.ACTION_DOWN
|| event.getAction() == MotionEvent.ACTION_UP) {
float y = event.getY();
if (y < 0.f) y = 0.f;
if (y > viewHue.getMeasuredHeight()) {
y = viewHue.getMeasuredHeight() - 0.001f; // to avoid jumping the cursor from bottom to top.
}
float hue = 360.f - 360.f / viewHue.getMeasuredHeight() * y;
if (hue == 360.f) hue = 0.f;
setHue(hue);
// update view
viewSatVal.setHue(getHue());
moveCursor();
viewNewColor.setBackgroundColor(getColor());
updateAlphaView();
return true;
}
return false;
});
if (supportsAlpha) viewAlphaCheckered.setOnTouchListener((v, event) -> {
if ((event.getAction() == MotionEvent.ACTION_MOVE)
|| (event.getAction() == MotionEvent.ACTION_DOWN)
|| (event.getAction() == MotionEvent.ACTION_UP)) {
float y = event.getY();
if (y < 0.f) {
y = 0.f;
}
if (y > viewAlphaCheckered.getMeasuredHeight()) {
y = viewAlphaCheckered.getMeasuredHeight() - 0.001f; // to avoid jumping the cursor from bottom to top.
}
final int a = Math.round(255.f - ((255.f / viewAlphaCheckered.getMeasuredHeight()) * y));
AmbilWarnaDialog.this.setAlpha(a);
// update view
moveAlphaCursor();
int col = AmbilWarnaDialog.this.getColor();
int c = a << 24 | col & 0x00ffffff;
viewNewColor.setBackgroundColor(c);
return true;
}
return false;
});
viewSatVal.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_MOVE
|| event.getAction() == MotionEvent.ACTION_DOWN
|| event.getAction() == MotionEvent.ACTION_UP) {
float x = event.getX(); // touch event are in dp units.
float y = event.getY();
if (x < 0.f) x = 0.f;
if (x > viewSatVal.getMeasuredWidth()) x = viewSatVal.getMeasuredWidth();
if (y < 0.f) y = 0.f;
if (y > viewSatVal.getMeasuredHeight()) y = viewSatVal.getMeasuredHeight();
setSat(1.f / viewSatVal.getMeasuredWidth() * x);
setVal(1.f - (1.f / viewSatVal.getMeasuredHeight() * y));
// update view
moveTarget();
viewNewColor.setBackgroundColor(getColor());
return true;
}
return false;
});
// move cursor & target on first draw
ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
moveCursor();
if (AmbilWarnaDialog.this.supportsAlpha) moveAlphaCursor();
moveTarget();
if (AmbilWarnaDialog.this.supportsAlpha) updateAlphaView();
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}
protected void moveCursor() {
float y = viewHue.getMeasuredHeight() - (getHue() * viewHue.getMeasuredHeight() / 360.f);
if (y == viewHue.getMeasuredHeight()) y = 0.f;
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) viewCursor.getLayoutParams();
layoutParams.leftMargin = (int) (viewHue.getLeft() - Math.floor(viewCursor.getMeasuredWidth() / 2) - viewContainer.getPaddingLeft());
layoutParams.topMargin = (int) (viewHue.getTop() + y - Math.floor(viewCursor.getMeasuredHeight() / 2) - viewContainer.getPaddingTop());
viewCursor.setLayoutParams(layoutParams);
}
protected void moveTarget() {
float x = getSat() * viewSatVal.getMeasuredWidth();
float y = (1.f - getVal()) * viewSatVal.getMeasuredHeight();
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) viewTarget.getLayoutParams();
layoutParams.leftMargin = (int) (viewSatVal.getLeft() + x - Math.floor(viewTarget.getMeasuredWidth() / 2) - viewContainer.getPaddingLeft());
layoutParams.topMargin = (int) (viewSatVal.getTop() + y - Math.floor(viewTarget.getMeasuredHeight() / 2) - viewContainer.getPaddingTop());
viewTarget.setLayoutParams(layoutParams);
}
protected void moveAlphaCursor() {
final int measuredHeight = this.viewAlphaCheckered.getMeasuredHeight();
float y = measuredHeight - ((this.getAlpha() * measuredHeight) / 255.f);
final RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) this.viewAlphaCursor.getLayoutParams();
layoutParams.leftMargin = (int) (this.viewAlphaCheckered.getLeft() - Math.floor(this.viewAlphaCursor.getMeasuredWidth() / 2) - this.viewContainer.getPaddingLeft());
layoutParams.topMargin = (int) ((this.viewAlphaCheckered.getTop() + y) - Math.floor(this.viewAlphaCursor.getMeasuredHeight() / 2) - this.viewContainer.getPaddingTop());
this.viewAlphaCursor.setLayoutParams(layoutParams);
}
private int getColor() {
final int argb = Color.HSVToColor(currentColorHsv);
return alpha << 24 | (argb & 0x00ffffff);
}
private float getHue() {
return currentColorHsv[0];
}
private float getAlpha() {
return this.alpha;
}
private float getSat() {
return currentColorHsv[1];
}
private float getVal() {
return currentColorHsv[2];
}
private void setHue(float hue) {
currentColorHsv[0] = hue;
}
private void setSat(float sat) {
currentColorHsv[1] = sat;
}
private void setAlpha(int alpha) {
this.alpha = alpha;
}
private void setVal(float val) {
currentColorHsv[2] = val;
}
public void show() {
dialog.show();
}
public Dialog getDialog() {
return dialog;
}
private void updateAlphaView() {
final GradientDrawable gd = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{
Color.HSVToColor(currentColorHsv), 0x0
});
viewAlphaOverlay.setBackgroundDrawable(gd);
}
}