blob: 1c62d9184f0bbc1d08fd7c286c9a61f101074001 [file] [log] [blame]
// Copyright 2010-2014, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package org.mozc.android.inputmethod.japanese.view;
import android.graphics.Canvas;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.PorterDuff.Mode;
import android.util.FloatMath;
/**
* Drawable to render a triangular highlight, whose vertices are the center and two adjacent
* vertices of the key background.
*
*/
public class TriangularHighlightDrawable extends BaseBackgroundDrawable {
public enum HighlightDirection {
LEFT, UP, RIGHT, DOWN,
}
// According to the original design mock, the ratio of the inner shadow width is about 0.046
// to height.
private static final float SHADE_LENGTH_RATIO = 0.046f;
private int baseColor;
private int shadeColor;
private final HighlightDirection direction;
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Path path = new Path();
public TriangularHighlightDrawable(
int leftPadding, int topPadding, int rightPadding, int bottomPadding,
int baseColor, int shadeColor, HighlightDirection direction) {
super(leftPadding, topPadding, rightPadding, bottomPadding);
this.baseColor = baseColor;
this.shadeColor = shadeColor;
this.direction = direction;
}
@Override
public void draw(Canvas canvas) {
canvas.drawPath(path, paint);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
Rect canvasRect = getCanvasRect();
switch (direction) {
case LEFT:
reset(canvasRect.exactCenterX(), canvasRect.exactCenterY(),
canvasRect.left, canvasRect.top, canvasRect.left, canvasRect.bottom,
canvasRect.height() * SHADE_LENGTH_RATIO);
break;
case UP:
reset(canvasRect.exactCenterX(), canvasRect.exactCenterY(),
canvasRect.right, canvasRect.top, canvasRect.left, canvasRect.top,
canvasRect.height() * SHADE_LENGTH_RATIO);
break;
case RIGHT:
reset(canvasRect.exactCenterX(), canvasRect.exactCenterY(),
canvasRect.right, canvasRect.bottom, canvasRect.right, canvasRect.top,
canvasRect.height() * SHADE_LENGTH_RATIO);
break;
case DOWN:
reset(canvasRect.exactCenterX(), canvasRect.exactCenterY(),
canvasRect.left, canvasRect.bottom, canvasRect.right, canvasRect.bottom,
canvasRect.height() * SHADE_LENGTH_RATIO);
break;
default:
throw new AssertionError();
}
}
/**
* Reset the internal paint and path based on given coordinates and shade's length.
* Note that it is necessary that the order of (centerX, centerY)-(x1, y1)-(x2, y2)
* is counter-clockwise.
*/
private void reset(
float centerX, float centerY, int x1, int y1, int x2, int y2, float shadeLength) {
resetPaint(centerX, centerY, x1, y1, x2, y2, shadeLength);
resetPath(centerX, centerY, x1, y1, x2, y2);
}
private void resetPaint(
float centerX, float centerY, int x1, int y1, int x2, int y2, float shadeLength) {
float dx1 = x1 - centerX;
float dy1 = y1 - centerY;
float shadeLengthRatio = shadeLength / FloatMath.sqrt(dx1 * dx1 + dy1 * dy1);
float nx1 = dy1 * shadeLengthRatio;
float ny1 = -dx1 * shadeLengthRatio;
LinearGradient gradient1 = new LinearGradient(
centerX, centerY, centerX + nx1, centerY + ny1,
shadeColor, baseColor, Shader.TileMode.CLAMP);
float dx2 = x2 - centerX;
float dy2 = y2 - centerY;
float nx2 = -dy2 * shadeLengthRatio;
float ny2 = dx2 * shadeLengthRatio;
LinearGradient gradient2 = new LinearGradient(
centerX, centerY, centerX + nx2, centerY + ny2,
shadeColor, baseColor, Shader.TileMode.CLAMP);
paint.setShader(new ComposeShader(gradient1, gradient2, Mode.DARKEN));
}
private void resetPath(float centerX, float centerY, int x1, int y1, int x2, int y2) {
// Create triangle path.
path.reset();
path.moveTo(centerX, centerY);
path.lineTo(x1, y1);
path.lineTo(x2, y2);
path.close();
}
}