blob: f799a18810fce0d83d4e841b7e7b99fda0f556b6 [file] [log] [blame]
/*
*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.android.draw9patch.ui;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
public class StretchesViewer extends JPanel {
public static final float DEFAULT_SCALE = 2.0f;
private static final int MARGIN = 24;
private final Container container;
private final ImageViewer viewer;
private final TexturePaint texture;
private BufferedImage image;
private PatchInfo patchInfo;
private StretchView horizontal;
private StretchView vertical;
private StretchView both;
private Dimension size;
private float horizontalPatchesSum;
private float verticalPatchesSum;
private boolean showPadding;
StretchesViewer(Container container, ImageViewer viewer, TexturePaint texture) {
this.container = container;
this.viewer = viewer;
this.texture = texture;
image = viewer.getImage();
patchInfo = viewer.getPatchInfo();
viewer.addPatchUpdateListener(new ImageViewer.PatchUpdateListener() {
@Override
public void patchesUpdated() {
computePatches();
}
});
setOpaque(false);
setLayout(new GridBagLayout());
setBorder(BorderFactory.createEmptyBorder(MARGIN, MARGIN, MARGIN, MARGIN));
horizontal = new StretchView();
vertical = new StretchView();
both = new StretchView();
setScale(DEFAULT_SCALE);
add(vertical, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
add(horizontal, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
add(both, new GridBagConstraints(0, 2, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(texture);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.dispose();
}
void setScale(float scale) {
int patchWidth = image.getWidth() - 2;
int patchHeight = image.getHeight() - 2;
int scaledWidth = (int) (patchWidth * scale);
int scaledHeight = (int) (patchHeight * scale);
horizontal.scaledWidth = scaledWidth;
vertical.scaledHeight = scaledHeight;
both.scaledWidth = scaledWidth;
both.scaledHeight = scaledHeight;
size = new Dimension(scaledWidth, scaledHeight);
computePatches();
}
void computePatches() {
image = viewer.getImage();
patchInfo = viewer.getPatchInfo();
boolean measuredWidth = false;
boolean endRow = true;
int remainderHorizontal = 0;
int remainderVertical = 0;
if (!patchInfo.fixed.isEmpty()) {
int start = patchInfo.fixed.get(0).y;
for (Rectangle rect : patchInfo.fixed) {
if (rect.y > start) {
endRow = true;
measuredWidth = true;
}
if (!measuredWidth) {
remainderHorizontal += rect.width;
}
if (endRow) {
remainderVertical += rect.height;
endRow = false;
start = rect.y;
}
}
} else {
/* fully stretched without fixed regions (often single pixel high or wide). Since
* width of vertical patches (and height of horizontal patches) are fixed, use them to
* determine fixed space
*/
for (Rectangle rect : patchInfo.verticalPatches) {
remainderHorizontal += rect.width;
}
for (Rectangle rect : patchInfo.horizontalPatches) {
remainderVertical += rect.height;
}
}
horizontal.remainderHorizontal = horizontal.scaledWidth - remainderHorizontal;
vertical.remainderHorizontal = vertical.scaledWidth - remainderHorizontal;
both.remainderHorizontal = both.scaledWidth - remainderHorizontal;
horizontal.remainderVertical = horizontal.scaledHeight - remainderVertical;
vertical.remainderVertical = vertical.scaledHeight - remainderVertical;
both.remainderVertical = both.scaledHeight - remainderVertical;
horizontalPatchesSum = 0;
if (patchInfo.horizontalPatches.size() > 0) {
int start = -1;
for (Rectangle rect : patchInfo.horizontalPatches) {
if (rect.x > start) {
horizontalPatchesSum += rect.width;
start = rect.x;
}
}
} else {
int start = -1;
for (Rectangle rect : patchInfo.patches) {
if (rect.x > start) {
horizontalPatchesSum += rect.width;
start = rect.x;
}
}
}
verticalPatchesSum = 0;
if (patchInfo.verticalPatches.size() > 0) {
int start = -1;
for (Rectangle rect : patchInfo.verticalPatches) {
if (rect.y > start) {
verticalPatchesSum += rect.height;
start = rect.y;
}
}
} else {
int start = -1;
for (Rectangle rect : patchInfo.patches) {
if (rect.y > start) {
verticalPatchesSum += rect.height;
start = rect.y;
}
}
}
setSize(size);
container.validate();
repaint();
}
void setPaddingVisible(boolean visible) {
showPadding = visible;
repaint();
}
private class StretchView extends JComponent {
private final Color PADDING_COLOR = new Color(0.37f, 0.37f, 1.0f, 0.5f);
int scaledWidth;
int scaledHeight;
int remainderHorizontal;
int remainderVertical;
StretchView() {
scaledWidth = image.getWidth();
scaledHeight = image.getHeight();
}
@Override
protected void paintComponent(Graphics g) {
int x = (getWidth() - scaledWidth) / 2;
int y = (getHeight() - scaledHeight) / 2;
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.translate(x, y);
x = 0;
y = 0;
if (patchInfo.patches.isEmpty()) {
g.drawImage(image, 0, 0, scaledWidth, scaledHeight, null);
g2.dispose();
return;
}
int fixedIndex = 0;
int horizontalIndex = 0;
int verticalIndex = 0;
int patchIndex = 0;
boolean hStretch;
boolean vStretch;
float vWeightSum = 1.0f;
float vRemainder = remainderVertical;
vStretch = patchInfo.verticalStartWithPatch;
while (y < scaledHeight - 1) {
hStretch = patchInfo.horizontalStartWithPatch;
int height = 0;
float vExtra = 0.0f;
float hWeightSum = 1.0f;
float hRemainder = remainderHorizontal;
while (x < scaledWidth - 1) {
Rectangle r;
if (!vStretch) {
if (hStretch) {
r = patchInfo.horizontalPatches.get(horizontalIndex++);
float extra = r.width / horizontalPatchesSum;
int width = (int) (extra * hRemainder / hWeightSum);
hWeightSum -= extra;
hRemainder -= width;
g.drawImage(image, x, y, x + width, y + r.height, r.x, r.y,
r.x + r.width, r.y + r.height, null);
x += width;
} else {
r = patchInfo.fixed.get(fixedIndex++);
g.drawImage(image, x, y, x + r.width, y + r.height, r.x, r.y,
r.x + r.width, r.y + r.height, null);
x += r.width;
}
height = r.height;
} else {
if (hStretch) {
r = patchInfo.patches.get(patchIndex++);
vExtra = r.height / verticalPatchesSum;
height = (int) (vExtra * vRemainder / vWeightSum);
float extra = r.width / horizontalPatchesSum;
int width = (int) (extra * hRemainder / hWeightSum);
hWeightSum -= extra;
hRemainder -= width;
g.drawImage(image, x, y, x + width, y + height, r.x, r.y,
r.x + r.width, r.y + r.height, null);
x += width;
} else {
r = patchInfo.verticalPatches.get(verticalIndex++);
vExtra = r.height / verticalPatchesSum;
height = (int) (vExtra * vRemainder / vWeightSum);
g.drawImage(image, x, y, x + r.width, y + height, r.x, r.y,
r.x + r.width, r.y + r.height, null);
x += r.width;
}
}
hStretch = !hStretch;
}
x = 0;
y += height;
if (vStretch) {
vWeightSum -= vExtra;
vRemainder -= height;
}
vStretch = !vStretch;
}
if (showPadding) {
g.setColor(PADDING_COLOR);
g.fillRect(patchInfo.horizontalPadding.first,
patchInfo.verticalPadding.first,
scaledWidth - patchInfo.horizontalPadding.first
- patchInfo.horizontalPadding.second,
scaledHeight - patchInfo.verticalPadding.first
- patchInfo.verticalPadding.second);
}
g2.dispose();
}
@Override
public Dimension getPreferredSize() {
return size;
}
}
}