/*
* Materialize - Materialize all those not material
* Copyright (C) 2015 XiNGRZ <xxx@oxo.ooo>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
package ooo.oxo.apps.materialize.graphics;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.annotation.Nullable;
public class InfiniteDrawable extends Drawable {
private final Bitmap left;
private final Bitmap top;
private final Bitmap right;
private final Bitmap bottom;
private final RectF regionLeft = new RectF();
private final RectF regionTop = new RectF();
private final RectF regionRight = new RectF();
private final RectF regionBottom = new RectF();
@ColorInt
private final int colorTL;
@ColorInt
private final int colorTR;
@ColorInt
private final int colorBL;
@ColorInt
private final int colorBR;
private final RectF regionTL = new RectF();
private final RectF regionTR = new RectF();
private final RectF regionBL = new RectF();
private final RectF regionBR = new RectF();
private final Paint paint = new Paint();
private float padding = 0;
public InfiniteDrawable(Bitmap left, Bitmap top, Bitmap right, Bitmap bottom,
@ColorInt int colorTL, @ColorInt int colorTR,
@ColorInt int colorBL, @ColorInt int colorBR) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
this.colorTL = colorTL;
this.colorTR = colorTR;
this.colorBL = colorBL;
this.colorBR = colorBR;
}
private static boolean isOpaque(@ColorInt int color) {
return Color.alpha(color) == 0xFF;
}
@Nullable
public static InfiniteDrawable from(Bitmap source) {
Bitmap left = Bitmap.createBitmap(1, source.getHeight(), Bitmap.Config.ARGB_8888);
Bitmap right = Bitmap.createBitmap(1, source.getHeight(), Bitmap.Config.ARGB_8888);
Bitmap top = Bitmap.createBitmap(source.getWidth(), 1, Bitmap.Config.ARGB_8888);
Bitmap bottom = Bitmap.createBitmap(source.getWidth(), 1, Bitmap.Config.ARGB_8888);
@ColorInt
int tl = Color.TRANSPARENT;
@ColorInt
int tr = Color.TRANSPARENT;
@ColorInt
int bl = Color.TRANSPARENT;
@ColorInt
int br = Color.TRANSPARENT;
// middle
for (int y = 0; y < source.getHeight(); y++) {
int color;
color = Color.TRANSPARENT;
for (int x = 0; x < source.getWidth() / 2; x++) {
int i = source.getPixel(x, y);
if (isOpaque(i)) {
color = i;
break;
}
}
left.setPixel(0, y, color);
color = Color.TRANSPARENT;
for (int x = source.getWidth() - 1; x > source.getWidth() / 2; x--) {
int i = source.getPixel(x, y);
if (isOpaque(i)) {
color = i;
break;
}
}
right.setPixel(0, y, color);
}
// top left
for (int y = 0; y < source.getHeight() / 2; y++) {
boolean opaque = false;
for (int x = source.getWidth() / 2; x >= 0; x--) {
int i = source.getPixel(x, y);
if (isOpaque(i)) {
top.setPixel(x, 0, tl = i);
opaque = true;
}
}
if (opaque) {
break;
}
}
// top right
for (int y = 0; y < source.getHeight() / 2; y++) {
boolean opaque = false;
for (int x = source.getWidth() / 2; x < source.getWidth(); x++) {
int i = source.getPixel(x, y);
if (isOpaque(i)) {
top.setPixel(x, 0, tr = i);
opaque = true;
}
}
if (opaque) {
break;
}
}
// bottom left
for (int y = source.getHeight() - 1; y > source.getHeight() / 2; y--) {
boolean opaque = false;
for (int x = source.getWidth() / 2; x >= 0; x--) {
int i = source.getPixel(x, y);
if (isOpaque(i)) {
bottom.setPixel(x, 0, bl = i);
opaque = true;
}
}
if (opaque) {
break;
}
}
// bottom right
for (int y = source.getHeight() - 1; y > source.getHeight() / 2; y--) {
boolean opaque = false;
for (int x = source.getWidth() / 2; x < source.getWidth(); x++) {
int i = source.getPixel(x, y);
if (isOpaque(i)) {
bottom.setPixel(x, 0, br = i);
opaque = true;
}
}
if (opaque) {
break;
}
}
return new InfiniteDrawable(left, top, right, bottom, tl, tr, bl, br);
}
public float getPadding() {
return padding;
}
public void setPadding(float padding) {
this.padding = padding;
invalidatePadding();
invalidateSelf();
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
invalidatePadding();
}
private void invalidatePadding() {
Rect bounds = getBounds();
regionTop.set(bounds.left + padding, bounds.top, bounds.right - padding, bounds.centerY());
regionBottom.set(bounds.left + padding, bounds.centerY(), bounds.right - padding, bounds.bottom);
regionLeft.set(bounds.left, bounds.top + padding, bounds.centerX(), bounds.bottom - padding);
regionRight.set(bounds.centerX(), bounds.top + padding, bounds.right, bounds.bottom - padding);
regionTL.set(bounds.left, bounds.top, bounds.centerX(), bounds.centerY());
regionTR.set(bounds.centerX(), bounds.top, bounds.right, bounds.centerY());
regionBL.set(bounds.left, bounds.centerY(), bounds.centerX(), bounds.bottom);
regionBR.set(bounds.centerX(), bounds.centerY(), bounds.right, bounds.bottom);
}
@Override
public void draw(Canvas canvas) {
paint.setColor(colorTL);
canvas.drawRect(regionTL, paint);
paint.setColor(colorTR);
canvas.drawRect(regionTR, paint);
paint.setColor(colorBL);
canvas.drawRect(regionBL, paint);
paint.setColor(colorBR);
canvas.drawRect(regionBR, paint);
canvas.drawBitmap(top, null, regionTop, null);
canvas.drawBitmap(bottom, null, regionBottom, null);
canvas.drawBitmap(left, null, regionLeft, null);
canvas.drawBitmap(right, null, regionRight, null);
}
@Override
public void setAlpha(int alpha) {
// not support
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
// not support
}
@Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
}