1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php 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 package com.android.ide.eclipse.adt.internal.editors.layout.gle2; 17 18 import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils.SHADOW_SIZE; 19 20 import org.eclipse.swt.events.SelectionAdapter; 21 import org.eclipse.swt.events.SelectionEvent; 22 import org.eclipse.swt.widgets.ScrollBar; 23 24 /** 25 * Helper class to convert between control pixel coordinates and canvas coordinates. 26 * Takes care of the zooming and offset of the canvas. 27 */ 28 public class CanvasTransform { 29 /** 30 * Default margin around the rendered image, reduced 31 * when the contents do not fit. 32 */ 33 public static final int DEFAULT_MARGIN = 25; 34 35 /** 36 * The canvas which controls the zooming. 37 */ 38 private final LayoutCanvas mCanvas; 39 40 /** Canvas image size (original, before zoom), in pixels. */ 41 private int mImgSize; 42 43 /** Full size being scrolled (after zoom), in pixels */ 44 private int mFullSize;; 45 46 /** Client size, in pixels. */ 47 private int mClientSize; 48 49 /** Left-top offset in client pixel coordinates. */ 50 private int mTranslate; 51 52 /** Current margin */ 53 private int mMargin = DEFAULT_MARGIN; 54 55 /** Scaling factor, > 0. */ 56 private double mScale; 57 58 /** Scrollbar widget. */ 59 private ScrollBar mScrollbar; 60 61 public CanvasTransform(LayoutCanvas layoutCanvas, ScrollBar scrollbar) { 62 mCanvas = layoutCanvas; 63 mScrollbar = scrollbar; 64 mScale = 1.0; 65 mTranslate = 0; 66 67 mScrollbar.addSelectionListener(new SelectionAdapter() { 68 @Override 69 public void widgetSelected(SelectionEvent e) { 70 // User requested scrolling. Changes translation and redraw canvas. 71 mTranslate = mScrollbar.getSelection(); 72 CanvasTransform.this.mCanvas.redraw(); 73 } 74 }); 75 mScrollbar.setIncrement(20); 76 } 77 78 /** 79 * Sets the new scaling factor. Recomputes scrollbars. 80 * @param scale Scaling factor, > 0. 81 */ 82 public void setScale(double scale) { 83 if (mScale != scale) { 84 mScale = scale; 85 resizeScrollbar(); 86 } 87 } 88 89 /** Recomputes the scrollbar and view port settings */ 90 public void refresh() { 91 resizeScrollbar(); 92 } 93 94 /** 95 * Returns current scaling factor. 96 * 97 * @return The current scaling factor 98 */ 99 public double getScale() { 100 return mScale; 101 } 102 103 /** 104 * Returns Canvas image size (original, before zoom), in pixels. 105 * 106 * @return Canvas image size (original, before zoom), in pixels 107 */ 108 public int getImgSize() { 109 return mImgSize; 110 } 111 112 /** 113 * Returns the scaled image size in pixels. 114 * 115 * @return The scaled image size in pixels. 116 */ 117 public int getScaledImgSize() { 118 return (int) (mImgSize * mScale); 119 } 120 121 /** 122 * Changes the size of the canvas image and the client size. Recomputes 123 * scrollbars. 124 * 125 * @param imgSize the size of the image being scaled 126 * @param fullSize the size of the full view area being scrolled 127 * @param clientSize the size of the view port 128 */ 129 public void setSize(int imgSize, int fullSize, int clientSize) { 130 mImgSize = imgSize; 131 mFullSize = fullSize; 132 mClientSize = clientSize; 133 mScrollbar.setPageIncrement(clientSize); 134 resizeScrollbar(); 135 } 136 137 private void resizeScrollbar() { 138 // scaled image size 139 int sx = (int) (mScale * mFullSize); 140 141 // Adjust margin such that for zoomed out views 142 // we don't waste space (unless the viewport is 143 // large enough to accommodate it) 144 int delta = mClientSize - sx; 145 if (delta < 0) { 146 mMargin = 0; 147 } else if (delta < 2 * DEFAULT_MARGIN) { 148 mMargin = delta / 2; 149 150 ImageOverlay imageOverlay = mCanvas.getImageOverlay(); 151 if (imageOverlay != null && imageOverlay.getShowDropShadow() 152 && delta >= SHADOW_SIZE / 2) { 153 mMargin -= SHADOW_SIZE / 2; 154 // Add a little padding on the top too, if there's room. The shadow assets 155 // include enough padding on the bottom to not make this look clipped. 156 if (mMargin < 4) { 157 mMargin += 4; 158 } 159 } 160 } else { 161 mMargin = DEFAULT_MARGIN; 162 } 163 164 if (mCanvas.getPreviewManager().hasPreviews()) { 165 // Make more room for the previews 166 mMargin = 2; 167 } 168 169 // actual client area is always reduced by the margins 170 int cx = mClientSize - 2 * mMargin; 171 172 if (sx < cx) { 173 mTranslate = 0; 174 mScrollbar.setEnabled(false); 175 } else { 176 mScrollbar.setEnabled(true); 177 178 int selection = mScrollbar.getSelection(); 179 int thumb = cx; 180 int maximum = sx; 181 182 if (selection + thumb > maximum) { 183 selection = maximum - thumb; 184 if (selection < 0) { 185 selection = 0; 186 } 187 } 188 189 mScrollbar.setValues(selection, mScrollbar.getMinimum(), maximum, thumb, mScrollbar 190 .getIncrement(), mScrollbar.getPageIncrement()); 191 192 mTranslate = selection; 193 } 194 } 195 196 public int getMargin() { 197 return mMargin; 198 } 199 200 public int translate(int canvasX) { 201 return mMargin - mTranslate + (int) (mScale * canvasX); 202 } 203 204 public int scale(int canwasW) { 205 return (int) (mScale * canwasW); 206 } 207 208 public int inverseTranslate(int screenX) { 209 return (int) ((screenX - mMargin + mTranslate) / mScale); 210 } 211 212 public int inverseScale(int canwasW) { 213 return (int) (canwasW / mScale); 214 } 215 } 216