1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.editors.draw9patch.ui; 18 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.internal.editors.draw9patch.graphics.GraphicsUtilities; 21 import com.android.ide.eclipse.adt.internal.editors.draw9patch.graphics.NinePatchedImage; 22 import com.android.ide.eclipse.adt.internal.editors.draw9patch.graphics.NinePatchedImage.Projection; 23 24 import org.eclipse.swt.SWT; 25 import org.eclipse.swt.events.PaintEvent; 26 import org.eclipse.swt.events.PaintListener; 27 import org.eclipse.swt.graphics.GC; 28 import org.eclipse.swt.graphics.Image; 29 import org.eclipse.swt.graphics.ImageData; 30 import org.eclipse.swt.graphics.PaletteData; 31 import org.eclipse.swt.graphics.Point; 32 import org.eclipse.swt.graphics.RGB; 33 import org.eclipse.swt.graphics.Rectangle; 34 import org.eclipse.swt.layout.FillLayout; 35 import org.eclipse.swt.widgets.Canvas; 36 import org.eclipse.swt.widgets.Composite; 37 38 /** 39 * Preview 9-patched image pane. 40 */ 41 public class StretchesViewer extends Composite { 42 private static final boolean DEBUG = false; 43 44 private static final int PADDING_COLOR = 0x0000CC; 45 46 private static final int PADDING_COLOR_ALPHA = 100; 47 48 private static final PaletteData PADDING_PALLET 49 = new PaletteData(new RGB[] {new RGB(0x00, 0x00, 0xCC)}); 50 51 private static final String CHECKER_PNG_PATH = "/icons/checker.png"; 52 53 private Image mBackgroundLayer = null; 54 55 private final StretchView mHorizontal; 56 private final StretchView mVertical; 57 58 private final StretchView mBoth; 59 60 private NinePatchedImage mNinePatchedImage = null; 61 62 private ImageData mContentAreaImageData = null; 63 64 private boolean mIsContentAreaShown = false; 65 66 private Image mContentAreaImage = null; 67 68 private int mScale = 2; 69 StretchesViewer(Composite parent, int style)70 public StretchesViewer(Composite parent, int style) { 71 super(parent, style); 72 73 mBackgroundLayer = AdtPlugin.getImageDescriptor(CHECKER_PNG_PATH).createImage(); 74 75 setLayout(new FillLayout(SWT.VERTICAL)); 76 77 mHorizontal = new StretchView(this, SWT.NULL); 78 mVertical = new StretchView(this, SWT.NULL); 79 mBoth = new StretchView(this, SWT.NULL); 80 } 81 82 /** 83 * Set show/not show content area. 84 * @param If show, true 85 */ setShowContentArea(boolean show)86 public void setShowContentArea(boolean show) { 87 mIsContentAreaShown = show; 88 redraw(); 89 } 90 equalSize(ImageData image1, ImageData image2)91 private static final boolean equalSize(ImageData image1, ImageData image2) { 92 return (image1.width == image2.width && image1.height == image2.height); 93 } 94 95 /** 96 * Update preview image. 97 */ updatePreview(NinePatchedImage image)98 public void updatePreview(NinePatchedImage image) { 99 mNinePatchedImage = image; 100 ImageData base = mNinePatchedImage.getImageData(); 101 102 if (mContentAreaImageData == null 103 || (mContentAreaImageData != null && !equalSize(base, mContentAreaImageData))) { 104 mContentAreaImageData = new ImageData( 105 base.width, 106 base.height, 107 1, 108 PADDING_PALLET); 109 } else { 110 GraphicsUtilities.clearImageData(mContentAreaImageData); 111 } 112 113 mHorizontal.setImage(mNinePatchedImage); 114 mVertical.setImage(mNinePatchedImage); 115 mBoth.setImage(mNinePatchedImage); 116 117 mContentAreaImage = buildContentAreaPreview(); 118 119 setScale(mScale); 120 } 121 buildContentAreaPreview()122 private Image buildContentAreaPreview() { 123 if (mContentAreaImage != null) { 124 mContentAreaImage.dispose(); 125 } 126 127 Rectangle rect = mNinePatchedImage.getContentArea(); 128 129 int yLen = rect.y + rect.height; 130 for (int y = rect.y; y < yLen; y++) { 131 int xLen = rect.x + rect.width; 132 for (int x = rect.x; x < xLen; x++) { 133 mContentAreaImageData.setPixel(x, y, PADDING_COLOR); 134 mContentAreaImageData.setAlpha(x, y, PADDING_COLOR_ALPHA); 135 } 136 } 137 return new Image(AdtPlugin.getDisplay(), mContentAreaImageData); 138 } 139 setScale(int scale)140 public void setScale(int scale) { 141 if (DEBUG) { 142 System.out.println("scale = " + scale); 143 } 144 145 mScale = scale; 146 int imageWidth = mNinePatchedImage.getWidth(); 147 int imageHeight = mNinePatchedImage.getHeight(); 148 149 mHorizontal.setSize(imageWidth * scale, imageHeight); 150 mVertical.setSize(imageWidth, imageHeight * scale); 151 mBoth.setSize(imageWidth * scale, imageHeight * scale); 152 153 redraw(); 154 } 155 156 @Override dispose()157 public void dispose() { 158 mBackgroundLayer.dispose(); 159 super.dispose(); 160 } 161 162 private class StretchView extends Canvas implements PaintListener { 163 164 private final Point mSize = new Point(0, 0); 165 private final Rectangle mPadding = new Rectangle(0, 0, 0, 0); 166 private Projection[][] mProjection = null; 167 StretchView(Composite parent, int style)168 public StretchView(Composite parent, int style) { 169 super(parent, style); 170 addPaintListener(this); 171 } 172 setImage(NinePatchedImage image)173 private void setImage(NinePatchedImage image) { 174 setSize(image.getWidth(), image.getHeight()); 175 } 176 177 @Override setSize(int width, int heigh)178 public void setSize(int width, int heigh) { 179 mSize.x = width; 180 mSize.y = heigh; 181 mProjection = mNinePatchedImage.getProjections(mSize.x, mSize.y, mProjection); 182 } 183 calcPaddings(int width, int height)184 private synchronized void calcPaddings(int width, int height) { 185 Point canvasSize = getSize(); 186 187 mPadding.x = (canvasSize.x - width) / 2; 188 mPadding.y = (canvasSize.y - height) / 2; 189 190 mPadding.width = width; 191 mPadding.height = height; 192 } 193 194 @Override paintControl(PaintEvent pe)195 public void paintControl(PaintEvent pe) { 196 if (mNinePatchedImage == null || mProjection == null) { 197 return; 198 } 199 200 Point size = getSize(); 201 202 // relative scaling 203 float ratio = 1.0f; 204 float wRatio = ((float) size.x / mSize.x); 205 ratio = Math.min(wRatio, ratio); 206 float hRatio = ((float) size.y / mSize.y); 207 ratio = Math.min(hRatio, ratio); 208 209 int width = Math.round(mSize.x * ratio); 210 int height = Math.round(mSize.y * ratio); 211 212 calcPaddings(width, height); 213 214 Rectangle dest = new Rectangle(0, 0, 0, 0); 215 216 GC gc = pe.gc; 217 218 int backgroundLayerWidth = mBackgroundLayer.getImageData().width; 219 int backgroundLayerHeight = mBackgroundLayer.getImageData().height; 220 221 int yCount = size.y / backgroundLayerHeight 222 + ((size.y % backgroundLayerHeight) > 0 ? 1 : 0); 223 int xCount = size.x / backgroundLayerWidth 224 + ((size.x % backgroundLayerWidth) > 0 ? 1 : 0); 225 226 // draw background layer 227 for (int y = 0; y < yCount; y++) { 228 for (int x = 0; x < xCount; x++) { 229 gc.drawImage(mBackgroundLayer, 230 x * backgroundLayerWidth, 231 y * backgroundLayerHeight); 232 } 233 } 234 235 // draw the border line 236 gc.setAlpha(0x88); 237 gc.drawRectangle(0, 0, size.x, size.y); 238 gc.setAlpha(0xFF); 239 240 int yLen = mProjection.length; 241 int xLen = mProjection[0].length; 242 for (int yPos = 0; yPos < yLen; yPos++) { 243 for (int xPos = 0; xPos < xLen; xPos++) { 244 Projection p = mProjection[yPos][xPos]; 245 246 // consider the scale 247 dest.x = (int) Math.ceil(p.dest.x * ratio); 248 dest.y = (int) Math.ceil(p.dest.y * ratio); 249 dest.width = (int) Math.ceil(p.dest.width * ratio); 250 dest.height = (int) Math.ceil(p.dest.height * ratio); 251 252 gc.drawImage(mNinePatchedImage.getImage(), p.src.x, p.src.y, 253 p.src.width, p.src.height, 254 (mPadding.x + dest.x), (mPadding.y + dest.y), 255 dest.width, dest.height); 256 257 if (mIsContentAreaShown) { 258 gc.drawImage(mContentAreaImage, p.src.x, p.src.y, 259 p.src.width, p.src.height, 260 (mPadding.x + dest.x), (mPadding.y + dest.y), 261 dest.width, dest.height); 262 } 263 } 264 } 265 } 266 } 267 } 268