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 org.eclipse.swt.SWT; 20 import org.eclipse.swt.events.SelectionAdapter; 21 import org.eclipse.swt.events.SelectionEvent; 22 import org.eclipse.swt.events.SelectionListener; 23 import org.eclipse.swt.graphics.GC; 24 import org.eclipse.swt.graphics.Image; 25 import org.eclipse.swt.graphics.Point; 26 import org.eclipse.swt.graphics.Rectangle; 27 import org.eclipse.swt.widgets.Canvas; 28 import org.eclipse.swt.widgets.Composite; 29 import org.eclipse.swt.widgets.Event; 30 import org.eclipse.swt.widgets.Listener; 31 import org.eclipse.swt.widgets.ScrollBar; 32 33 public class ImageCanvas extends Canvas { 34 private static final int SCROLLBAR_INCREMENT = 20; 35 36 private Point mOrigin; 37 38 private ScrollBar mHorizontalScrollBar; 39 private ScrollBar mVerticalScrollBar; 40 41 private Image mImage; 42 private boolean mFitToCanvas; 43 ImageCanvas(Composite parent)44 public ImageCanvas(Composite parent) { 45 super(parent, SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL); 46 mOrigin = new Point(0, 0); 47 48 mHorizontalScrollBar = getHorizontalBar(); 49 mVerticalScrollBar = getVerticalBar(); 50 51 mFitToCanvas = true; 52 53 setScrollBarIncrements(); 54 setScrollBarPageIncrements(getClientArea()); 55 56 updateScrollBars(); 57 58 SelectionListener scrollBarSelectionListener = new SelectionAdapter() { 59 @Override 60 public void widgetSelected(SelectionEvent e) { 61 if (e.getSource() == mHorizontalScrollBar) { 62 scrollHorizontally(); 63 } else { 64 scrollVertically(); 65 } 66 } 67 }; 68 69 mHorizontalScrollBar.addSelectionListener(scrollBarSelectionListener); 70 mVerticalScrollBar.addSelectionListener(scrollBarSelectionListener); 71 72 addListener(SWT.Resize, new Listener() { 73 @Override 74 public void handleEvent(Event e) { 75 setScrollBarPageIncrements(getClientArea()); 76 updateScrollBars(); 77 } 78 }); 79 80 addListener(SWT.Paint, new Listener() { 81 @Override 82 public void handleEvent(Event e) { 83 paintCanvas(e.gc); 84 } 85 }); 86 } 87 setFitToCanvas(boolean en)88 public void setFitToCanvas(boolean en) { 89 mFitToCanvas = en; 90 updateScrollBars(); 91 redraw(); 92 } 93 setImage(Image image)94 public void setImage(Image image) { 95 if (mImage != null) { 96 mImage.dispose(); 97 } 98 99 mImage = image; 100 mOrigin = new Point(0, 0); 101 updateScrollBars(); 102 redraw(); 103 } 104 updateScrollBars()105 private void updateScrollBars() { 106 Rectangle client = getClientArea(); 107 108 int imageWidth, imageHeight; 109 if (mImage != null & !mFitToCanvas) { 110 imageWidth = mImage.getBounds().width; 111 imageHeight = mImage.getBounds().height; 112 } else { 113 imageWidth = client.width; 114 imageHeight = client.height; 115 } 116 117 mHorizontalScrollBar.setMaximum(imageWidth); 118 mVerticalScrollBar.setMaximum(imageHeight); 119 mHorizontalScrollBar.setThumb(Math.min(imageWidth, client.width)); 120 mVerticalScrollBar.setThumb(Math.min(imageHeight, client.height)); 121 122 int hPage = imageWidth - client.width; 123 int vPage = imageHeight - client.height; 124 int hSelection = mHorizontalScrollBar.getSelection(); 125 int vSelection = mVerticalScrollBar.getSelection(); 126 if (hSelection >= hPage) { 127 if (hPage <= 0) { 128 hSelection = 0; 129 } 130 mOrigin.x = -hSelection; 131 } 132 133 if (vSelection >= vPage) { 134 if (vPage <= 0) { 135 vSelection = 0; 136 } 137 mOrigin.y = -vSelection; 138 } 139 140 redraw(); 141 } 142 setScrollBarPageIncrements(Rectangle clientArea)143 private void setScrollBarPageIncrements(Rectangle clientArea) { 144 mHorizontalScrollBar.setPageIncrement(clientArea.width); 145 mVerticalScrollBar.setPageIncrement(clientArea.height); 146 } 147 setScrollBarIncrements()148 private void setScrollBarIncrements() { 149 // The default increment is 1 pixel. Assign a saner default. 150 mHorizontalScrollBar.setIncrement(SCROLLBAR_INCREMENT); 151 mVerticalScrollBar.setIncrement(SCROLLBAR_INCREMENT); 152 } 153 scrollHorizontally()154 private void scrollHorizontally() { 155 if (mImage == null) { 156 return; 157 } 158 159 int selection = mHorizontalScrollBar.getSelection(); 160 int destX = -selection - mOrigin.x; 161 Rectangle imageBounds = mImage.getBounds(); 162 scroll(destX, 0, 0, 0, imageBounds.width, imageBounds.height, false); 163 mOrigin.x = -selection; 164 } 165 scrollVertically()166 private void scrollVertically() { 167 if (mImage == null) { 168 return; 169 } 170 171 int selection = mVerticalScrollBar.getSelection(); 172 int destY = -selection - mOrigin.y; 173 Rectangle imageBounds = mImage.getBounds(); 174 scroll(0, destY, 0, 0, imageBounds.width, imageBounds.height, false); 175 mOrigin.y = -selection; 176 } 177 paintCanvas(GC gc)178 private void paintCanvas(GC gc) { 179 gc.fillRectangle(getClientArea()); 180 if (mImage == null) { 181 return; 182 } 183 184 Rectangle rect = mImage.getBounds(); 185 Rectangle client = getClientArea(); 186 187 if (mFitToCanvas && rect.width > 0 && rect.height > 0) { 188 double sx = (double) client.width / (double) rect.width; 189 double sy = (double) client.height / (double) rect.height; 190 191 if (sx < sy) { 192 // if we need to scale more horizontally, then reduce the client height 193 // appropriately so that aspect ratios are maintained 194 gc.drawImage(mImage, 195 0, 0, rect.width, rect.height, 196 0, 0, client.width, (int)(rect.height * sx)); 197 } else { 198 // scale client width to maintain aspect ratio 199 gc.drawImage(mImage, 200 0, 0, rect.width, rect.height, 201 0, 0, (int)(rect.width * sy), client.height); 202 } 203 } else { 204 gc.drawImage(mImage, mOrigin.x, mOrigin.y); 205 } 206 } 207 208 @Override dispose()209 public void dispose() { 210 if (mImage != null && !mImage.isDisposed()) { 211 mImage.dispose(); 212 } 213 } 214 } 215