1 /* 2 * Copyright (C) 2012 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.gltrace.widgets; 18 19 import com.android.ide.eclipse.gltrace.GlTracePlugin; 20 21 import org.eclipse.core.runtime.Status; 22 import org.eclipse.jface.dialogs.ErrorDialog; 23 import org.eclipse.swt.SWT; 24 import org.eclipse.swt.events.SelectionAdapter; 25 import org.eclipse.swt.events.SelectionEvent; 26 import org.eclipse.swt.events.SelectionListener; 27 import org.eclipse.swt.graphics.Color; 28 import org.eclipse.swt.graphics.GC; 29 import org.eclipse.swt.graphics.Image; 30 import org.eclipse.swt.graphics.ImageData; 31 import org.eclipse.swt.graphics.ImageLoader; 32 import org.eclipse.swt.graphics.Point; 33 import org.eclipse.swt.graphics.Rectangle; 34 import org.eclipse.swt.widgets.Canvas; 35 import org.eclipse.swt.widgets.Composite; 36 import org.eclipse.swt.widgets.Display; 37 import org.eclipse.swt.widgets.Event; 38 import org.eclipse.swt.widgets.Listener; 39 import org.eclipse.swt.widgets.ScrollBar; 40 41 import java.io.File; 42 43 public class ImageCanvas extends Canvas { 44 private static final int SCROLLBAR_INCREMENT = 20; 45 46 private Point mOrigin; 47 48 private ScrollBar mHorizontalScrollBar; 49 private ScrollBar mVerticalScrollBar; 50 51 private Image mImage; 52 private boolean mFitToCanvas; 53 ImageCanvas(Composite parent)54 public ImageCanvas(Composite parent) { 55 super(parent, SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL); 56 mOrigin = new Point(0, 0); 57 58 mHorizontalScrollBar = getHorizontalBar(); 59 mVerticalScrollBar = getVerticalBar(); 60 61 mFitToCanvas = true; 62 63 setScrollBarIncrements(); 64 setScrollBarPageIncrements(getClientArea()); 65 66 updateScrollBars(); 67 68 SelectionListener scrollBarSelectionListener = new SelectionAdapter() { 69 @Override 70 public void widgetSelected(SelectionEvent e) { 71 if (e.getSource() == mHorizontalScrollBar) { 72 scrollHorizontally(); 73 } else { 74 scrollVertically(); 75 } 76 } 77 }; 78 79 mHorizontalScrollBar.addSelectionListener(scrollBarSelectionListener); 80 mVerticalScrollBar.addSelectionListener(scrollBarSelectionListener); 81 82 addListener(SWT.Resize, new Listener() { 83 @Override 84 public void handleEvent(Event e) { 85 setScrollBarPageIncrements(getClientArea()); 86 updateScrollBars(); 87 } 88 }); 89 90 addListener(SWT.Paint, new Listener() { 91 @Override 92 public void handleEvent(Event e) { 93 paintCanvas(e.gc); 94 } 95 }); 96 } 97 setFitToCanvas(boolean en)98 public void setFitToCanvas(boolean en) { 99 mFitToCanvas = en; 100 updateScrollBars(); 101 redraw(); 102 } 103 setImage(Image image)104 public void setImage(Image image) { 105 if (mImage != null) { 106 mImage.dispose(); 107 } 108 109 mImage = image; 110 mOrigin = new Point(0, 0); 111 updateScrollBars(); 112 redraw(); 113 } 114 updateScrollBars()115 private void updateScrollBars() { 116 Rectangle client = getClientArea(); 117 118 int imageWidth, imageHeight; 119 if (mImage != null & !mFitToCanvas) { 120 imageWidth = mImage.getBounds().width; 121 imageHeight = mImage.getBounds().height; 122 } else { 123 imageWidth = client.width; 124 imageHeight = client.height; 125 } 126 127 mHorizontalScrollBar.setMaximum(imageWidth); 128 mVerticalScrollBar.setMaximum(imageHeight); 129 mHorizontalScrollBar.setThumb(Math.min(imageWidth, client.width)); 130 mVerticalScrollBar.setThumb(Math.min(imageHeight, client.height)); 131 132 int hPage = imageWidth - client.width; 133 int vPage = imageHeight - client.height; 134 int hSelection = mHorizontalScrollBar.getSelection(); 135 int vSelection = mVerticalScrollBar.getSelection(); 136 if (hSelection >= hPage) { 137 if (hPage <= 0) { 138 hSelection = 0; 139 } 140 mOrigin.x = -hSelection; 141 } 142 143 if (vSelection >= vPage) { 144 if (vPage <= 0) { 145 vSelection = 0; 146 } 147 mOrigin.y = -vSelection; 148 } 149 150 redraw(); 151 } 152 setScrollBarPageIncrements(Rectangle clientArea)153 private void setScrollBarPageIncrements(Rectangle clientArea) { 154 mHorizontalScrollBar.setPageIncrement(clientArea.width); 155 mVerticalScrollBar.setPageIncrement(clientArea.height); 156 } 157 setScrollBarIncrements()158 private void setScrollBarIncrements() { 159 // The default increment is 1 pixel. Assign a saner default. 160 mHorizontalScrollBar.setIncrement(SCROLLBAR_INCREMENT); 161 mVerticalScrollBar.setIncrement(SCROLLBAR_INCREMENT); 162 } 163 scrollHorizontally()164 private void scrollHorizontally() { 165 if (mImage == null) { 166 return; 167 } 168 169 int selection = mHorizontalScrollBar.getSelection(); 170 int destX = -selection - mOrigin.x; 171 Rectangle imageBounds = mImage.getBounds(); 172 scroll(destX, 0, 0, 0, imageBounds.width, imageBounds.height, false); 173 mOrigin.x = -selection; 174 } 175 scrollVertically()176 private void scrollVertically() { 177 if (mImage == null) { 178 return; 179 } 180 181 int selection = mVerticalScrollBar.getSelection(); 182 int destY = -selection - mOrigin.y; 183 Rectangle imageBounds = mImage.getBounds(); 184 scroll(0, destY, 0, 0, imageBounds.width, imageBounds.height, false); 185 mOrigin.y = -selection; 186 } 187 paintCanvas(GC gc)188 private void paintCanvas(GC gc) { 189 gc.fillRectangle(getClientArea()); // clear entire client area 190 if (mImage == null) { 191 return; 192 } 193 194 Rectangle rect = mImage.getBounds(); 195 Rectangle client = getClientArea(); 196 197 if (mFitToCanvas && rect.width > 0 && rect.height > 0) { 198 double sx = (double) client.width / (double) rect.width; 199 double sy = (double) client.height / (double) rect.height; 200 201 if (sx < sy) { 202 // if we need to scale more horizontally, then reduce the client height 203 // appropriately so that aspect ratios are maintained 204 gc.drawImage(mImage, 205 0, 0, rect.width, rect.height, 206 0, 0, client.width, (int)(rect.height * sx)); 207 drawBorder(gc, 0, 0, client.width, (int)(rect.height * sx)); 208 } else { 209 // scale client width to maintain aspect ratio 210 gc.drawImage(mImage, 211 0, 0, rect.width, rect.height, 212 0, 0, (int)(rect.width * sy), client.height); 213 drawBorder(gc, 0, 0, (int)(rect.width * sy), client.height); 214 } 215 } else { 216 gc.drawImage(mImage, mOrigin.x, mOrigin.y); 217 drawBorder(gc, mOrigin.x, mOrigin.y, rect.width, rect.height); 218 } 219 } 220 drawBorder(GC gc, int x, int y, int width, int height)221 private void drawBorder(GC gc, int x, int y, int width, int height) { 222 Color origFg = gc.getForeground(); 223 gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW)); 224 gc.drawRectangle(x, y, width, height); 225 gc.setForeground(origFg); 226 } 227 228 @Override dispose()229 public void dispose() { 230 if (mImage != null && !mImage.isDisposed()) { 231 mImage.dispose(); 232 } 233 } 234 exportImageTo(File file)235 public void exportImageTo(File file) { 236 if (mImage == null || file == null) { 237 return; 238 } 239 240 ImageLoader imageLoader = new ImageLoader(); 241 imageLoader.data = new ImageData[] { mImage.getImageData() }; 242 243 try { 244 imageLoader.save(file.getAbsolutePath(), SWT.IMAGE_PNG); 245 } catch (Exception e) { 246 ErrorDialog.openError(getShell(), "Save Image", "Error saving image", 247 new Status(Status.ERROR, GlTracePlugin.PLUGIN_ID, e.toString())); 248 } 249 } 250 } 251