Home | History | Annotate | Download | only in ui
      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 
     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      */
     86     public void setShowContentArea(boolean show) {
     87         mIsContentAreaShown = show;
     88         redraw();
     89     }
     90 
     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      */
     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 
    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 
    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
    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 
    168         public StretchView(Composite parent, int style) {
    169             super(parent, style);
    170             addPaintListener(this);
    171         }
    172 
    173         private void setImage(NinePatchedImage image) {
    174             setSize(image.getWidth(), image.getHeight());
    175         }
    176 
    177         @Override
    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 
    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
    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