NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterCurvesControl.java

323 lines
11 KiB
Java

/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.ui.Components;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.text.TextPaint;
import android.view.MotionEvent;
import android.view.View;
import org.telegram.messenger.AndroidUtilities;
import java.util.Locale;
public class PhotoFilterCurvesControl extends View {
public interface PhotoFilterCurvesControlDelegate {
void valueChanged();
}
private final static int CurvesSegmentNone = 0;
private final static int CurvesSegmentBlacks = 1;
private final static int CurvesSegmentShadows = 2;
private final static int CurvesSegmentMidtones = 3;
private final static int CurvesSegmentHighlights = 4;
private final static int CurvesSegmentWhites = 5;
private final static int GestureStateBegan = 1;
private final static int GestureStateChanged = 2;
private final static int GestureStateEnded = 3;
private final static int GestureStateCancelled = 4;
private final static int GestureStateFailed = 5;
private int activeSegment = CurvesSegmentNone;
private boolean isMoving;
private boolean checkForMoving = true;
private float lastX;
private float lastY;
private Rect actualArea = new Rect();
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint paintDash = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint paintCurve = new Paint(Paint.ANTI_ALIAS_FLAG);
private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
private Path path = new Path();
private PhotoFilterCurvesControlDelegate delegate;
private PhotoFilterView.CurvesToolValue curveValue;
public PhotoFilterCurvesControl(Context context, PhotoFilterView.CurvesToolValue value) {
super(context);
setWillNotDraw(false);
curveValue = value;
paint.setColor(0x99ffffff);
paint.setStrokeWidth(AndroidUtilities.dp(1));
paint.setStyle(Paint.Style.STROKE);
paintDash.setColor(0x99ffffff);
paintDash.setStrokeWidth(AndroidUtilities.dp(2));
paintDash.setStyle(Paint.Style.STROKE);
paintCurve.setColor(0xffffffff);
paintCurve.setStrokeWidth(AndroidUtilities.dp(2));
paintCurve.setStyle(Paint.Style.STROKE);
textPaint.setColor(0xffbfbfbf);
textPaint.setTextSize(AndroidUtilities.dp(13));
}
public void setDelegate(PhotoFilterCurvesControlDelegate photoFilterCurvesControlDelegate) {
delegate = photoFilterCurvesControlDelegate;
}
public void setActualArea(float x, float y, float width, float height) {
actualArea.x = x;
actualArea.y = y;
actualArea.width = width;
actualArea.height = height;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_DOWN: {
if (event.getPointerCount() == 1) {
if (checkForMoving && !isMoving) {
float locationX = event.getX();
float locationY = event.getY();
lastX = locationX;
lastY = locationY;
if (locationX >= actualArea.x && locationX <= actualArea.x + actualArea.width && locationY >= actualArea.y && locationY <= actualArea.y + actualArea.height) {
isMoving = true;
}
checkForMoving = false;
if (isMoving) {
handlePan(GestureStateBegan, event);
}
}
} else {
if (isMoving) {
handlePan(GestureStateEnded, event);
checkForMoving = true;
isMoving = false;
}
}
break;
}
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
if (isMoving) {
handlePan(GestureStateEnded, event);
isMoving = false;
}
checkForMoving = true;
break;
}
case MotionEvent.ACTION_MOVE: {
if (isMoving) {
handlePan(GestureStateChanged, event);
}
}
}
return true;
}
private void handlePan(int state, MotionEvent event) {
float locationX = event.getX();
float locationY = event.getY();
switch (state) {
case GestureStateBegan: {
selectSegmentWithPoint(locationX);
break;
}
case GestureStateChanged: {
float delta = Math.min(2, (lastY - locationY) / 8.0f);
PhotoFilterView.CurvesValue curveValue = null;
switch (this.curveValue.activeType) {
case PhotoFilterView.CurvesToolValue.CurvesTypeLuminance:
curveValue = this.curveValue.luminanceCurve;
break;
case PhotoFilterView.CurvesToolValue.CurvesTypeRed:
curveValue = this.curveValue.redCurve;
break;
case PhotoFilterView.CurvesToolValue.CurvesTypeGreen:
curveValue = this.curveValue.greenCurve;
break;
case PhotoFilterView.CurvesToolValue.CurvesTypeBlue:
curveValue = this.curveValue.blueCurve;
break;
default:
break;
}
switch (activeSegment) {
case CurvesSegmentBlacks:
curveValue.blacksLevel = Math.max(0, Math.min(100, curveValue.blacksLevel + delta));
break;
case CurvesSegmentShadows:
curveValue.shadowsLevel = Math.max(0, Math.min(100, curveValue.shadowsLevel + delta));
break;
case CurvesSegmentMidtones:
curveValue.midtonesLevel = Math.max(0, Math.min(100, curveValue.midtonesLevel + delta));
break;
case CurvesSegmentHighlights:
curveValue.highlightsLevel = Math.max(0, Math.min(100, curveValue.highlightsLevel + delta));
break;
case CurvesSegmentWhites:
curveValue.whitesLevel = Math.max(0, Math.min(100, curveValue.whitesLevel + delta));
break;
default:
break;
}
invalidate();
if (delegate != null) {
delegate.valueChanged();
}
lastX = locationX;
lastY = locationY;
}
break;
case GestureStateEnded:
case GestureStateCancelled:
case GestureStateFailed: {
unselectSegments();
}
break;
default:
break;
}
}
private void selectSegmentWithPoint(float pointx) {
if (activeSegment != CurvesSegmentNone) {
return;
}
float segmentWidth = actualArea.width / 5.0f;
pointx -= actualArea.x;
activeSegment = (int) Math.floor((pointx / segmentWidth) + 1);
}
private void unselectSegments() {
if (activeSegment == CurvesSegmentNone) {
return;
}
activeSegment = CurvesSegmentNone;
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
float segmentWidth = actualArea.width / 5.0f;
for (int i = 0; i < 4; i++) {
canvas.drawLine(actualArea.x + segmentWidth + i * segmentWidth, actualArea.y, actualArea.x + segmentWidth + i * segmentWidth, actualArea.y + actualArea.height, paint);
}
canvas.drawLine(actualArea.x, actualArea.y + actualArea.height, actualArea.x + actualArea.width, actualArea.y, paintDash);
PhotoFilterView.CurvesValue curvesValue = null;
switch (curveValue.activeType) {
case PhotoFilterView.CurvesToolValue.CurvesTypeLuminance:
paintCurve.setColor(0xffffffff);
curvesValue = curveValue.luminanceCurve;
break;
case PhotoFilterView.CurvesToolValue.CurvesTypeRed:
paintCurve.setColor(0xffed3d4c);
curvesValue = curveValue.redCurve;
break;
case PhotoFilterView.CurvesToolValue.CurvesTypeGreen:
paintCurve.setColor(0xff10ee9d);
curvesValue = curveValue.greenCurve;
break;
case PhotoFilterView.CurvesToolValue.CurvesTypeBlue:
paintCurve.setColor(0xff3377fb);
curvesValue = curveValue.blueCurve;
break;
default:
break;
}
for (int a = 0; a < 5; a++) {
String str;
switch (a) {
case 0:
str = String.format(Locale.US, "%.2f", curvesValue.blacksLevel / 100.0f);
break;
case 1:
str = String.format(Locale.US, "%.2f", curvesValue.shadowsLevel / 100.0f);
break;
case 2:
str = String.format(Locale.US, "%.2f", curvesValue.midtonesLevel / 100.0f);
break;
case 3:
str = String.format(Locale.US, "%.2f", curvesValue.highlightsLevel / 100.0f);
break;
case 4:
str = String.format(Locale.US, "%.2f", curvesValue.whitesLevel / 100.0f);
break;
default:
str = "";
break;
}
float width = textPaint.measureText(str);
canvas.drawText(str, actualArea.x + (segmentWidth - width) / 2 + segmentWidth * a, actualArea.y + actualArea.height - AndroidUtilities.dp(4), textPaint);
}
float[] points = curvesValue.interpolateCurve();
invalidate();
path.reset();
for (int a = 0; a < points.length / 2; a++) {
if (a == 0) {
path.moveTo(actualArea.x + points[a * 2] * actualArea.width, actualArea.y + (1.0f - points[a * 2 + 1]) * actualArea.height);
} else {
path.lineTo(actualArea.x + points[a * 2] * actualArea.width, actualArea.y + (1.0f - points[a * 2 + 1]) * actualArea.height);
}
}
canvas.drawPath(path, paintCurve);
}
}