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 
CanvasTransform(LayoutCanvas layoutCanvas, ScrollBar scrollbar)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      */
setScale(double scale)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 */
refresh()90     public void refresh() {
91         resizeScrollbar();
92     }
93 
94     /**
95      * Returns current scaling factor.
96      *
97      * @return The current scaling factor
98      */
getScale()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      */
getImgSize()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      */
getScaledImgSize()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      */
setSize(int imgSize, int fullSize, int clientSize)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 
resizeScrollbar()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 
getMargin()196     public int getMargin() {
197         return mMargin;
198     }
199 
translate(int canvasX)200     public int translate(int canvasX) {
201         return mMargin - mTranslate + (int) (mScale * canvasX);
202     }
203 
scale(int canwasW)204     public int scale(int canwasW) {
205         return (int) (mScale * canwasW);
206     }
207 
inverseTranslate(int screenX)208     public int inverseTranslate(int screenX) {
209         return (int) ((screenX - mMargin + mTranslate) / mScale);
210     }
211 
inverseScale(int canwasW)212     public int inverseScale(int canwasW) {
213         return (int) (canwasW / mScale);
214     }
215 }
216