create changelog entry
[debian/openrocket] / android-libraries / achartengine / src / org / achartengine / GraphicalView.java
1 /**\r
2  * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
3  *  \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *  \r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *  \r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 package org.achartengine;\r
17 \r
18 import org.achartengine.chart.AbstractChart;\r
19 import org.achartengine.chart.RoundChart;\r
20 import org.achartengine.chart.XYChart;\r
21 import org.achartengine.model.Point;\r
22 import org.achartengine.model.SeriesSelection;\r
23 import org.achartengine.renderer.DefaultRenderer;\r
24 import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
25 import org.achartengine.tools.FitZoom;\r
26 import org.achartengine.tools.PanListener;\r
27 import org.achartengine.tools.Zoom;\r
28 import org.achartengine.tools.ZoomListener;\r
29 \r
30 import android.content.Context;\r
31 import android.graphics.Bitmap;\r
32 import android.graphics.BitmapFactory;\r
33 import android.graphics.Canvas;\r
34 import android.graphics.Color;\r
35 import android.graphics.Paint;\r
36 import android.graphics.Rect;\r
37 import android.graphics.RectF;\r
38 import android.os.Build;\r
39 import android.os.Handler;\r
40 import android.view.MotionEvent;\r
41 import android.view.View;\r
42 \r
43 /**\r
44  * The view that encapsulates the graphical chart.\r
45  */\r
46 public class GraphicalView extends View {\r
47   /** The chart to be drawn. */\r
48   private AbstractChart mChart;\r
49   /** The chart renderer. */\r
50   private DefaultRenderer mRenderer;\r
51   /** The view bounds. */\r
52   private Rect mRect = new Rect();\r
53   /** The user interface thread handler. */\r
54   private Handler mHandler;\r
55   /** The zoom buttons rectangle. */\r
56   private RectF mZoomR = new RectF();\r
57   /** The zoom in icon. */\r
58   private Bitmap zoomInImage;\r
59   /** The zoom out icon. */\r
60   private Bitmap zoomOutImage;\r
61   /** The fit zoom icon. */\r
62   private Bitmap fitZoomImage;\r
63   /** The zoom area size. */\r
64   private int zoomSize = 50;\r
65   /** The zoom buttons background color. */\r
66   private static final int ZOOM_BUTTONS_COLOR = Color.argb(175, 150, 150, 150);\r
67   /** The zoom in tool. */\r
68   private Zoom mZoomIn;\r
69   /** The zoom out tool. */\r
70   private Zoom mZoomOut;\r
71   /** The fit zoom tool. */\r
72   private FitZoom mFitZoom;\r
73   /** The paint to be used when drawing the chart. */\r
74   private Paint mPaint = new Paint();\r
75   /** The touch handler. */\r
76   private ITouchHandler mTouchHandler;\r
77   /** The old x coordinate. */\r
78   private float oldX;\r
79   /** The old y coordinate. */\r
80   private float oldY;\r
81 \r
82   /**\r
83    * Creates a new graphical view.\r
84    * \r
85    * @param context the context\r
86    * @param chart the chart to be drawn\r
87    */\r
88   public GraphicalView(Context context, AbstractChart chart) {\r
89     super(context);\r
90     mChart = chart;\r
91     mHandler = new Handler();\r
92     if (mChart instanceof XYChart) {\r
93       mRenderer = ((XYChart) mChart).getRenderer();\r
94     } else {\r
95       mRenderer = ((RoundChart) mChart).getRenderer();\r
96     }\r
97     if (mRenderer.isZoomButtonsVisible()) {\r
98       zoomInImage = BitmapFactory.decodeStream(GraphicalView.class\r
99           .getResourceAsStream("image/zoom_in.png"));\r
100       zoomOutImage = BitmapFactory.decodeStream(GraphicalView.class\r
101           .getResourceAsStream("image/zoom_out.png"));\r
102       fitZoomImage = BitmapFactory.decodeStream(GraphicalView.class\r
103           .getResourceAsStream("image/zoom-1.png"));\r
104     }\r
105 \r
106     if (mRenderer instanceof XYMultipleSeriesRenderer\r
107         && ((XYMultipleSeriesRenderer) mRenderer).getMarginsColor() == XYMultipleSeriesRenderer.NO_COLOR) {\r
108       ((XYMultipleSeriesRenderer) mRenderer).setMarginsColor(mPaint.getColor());\r
109     }\r
110     if (mRenderer.isZoomEnabled() && mRenderer.isZoomButtonsVisible()\r
111         || mRenderer.isExternalZoomEnabled()) {\r
112       mZoomIn = new Zoom(mChart, true, mRenderer.getZoomRate());\r
113       mZoomOut = new Zoom(mChart, false, mRenderer.getZoomRate());\r
114       mFitZoom = new FitZoom(mChart);\r
115     }\r
116     int version = 7;\r
117     try {\r
118       version = Integer.valueOf(Build.VERSION.SDK);\r
119     } catch (Exception e) {\r
120       // do nothing\r
121     }\r
122     if (version < 7) {\r
123       mTouchHandler = new TouchHandlerOld(this, mChart);\r
124     } else {\r
125       mTouchHandler = new TouchHandler(this, mChart);\r
126     }\r
127   }\r
128 \r
129   /**\r
130    * Returns the current series selection object.\r
131    * \r
132    * @return the series selection\r
133    */\r
134   public SeriesSelection getCurrentSeriesAndPoint() {\r
135     return mChart.getSeriesAndPointForScreenCoordinate(new Point(oldX, oldY));\r
136   }\r
137 \r
138   /**\r
139    * Transforms the currently selected screen point to a real point.\r
140    * \r
141    * @param scale the scale\r
142    * @return the currently selected real point\r
143    */\r
144   public double[] toRealPoint(int scale) {\r
145     if (mChart instanceof XYChart) {\r
146       XYChart chart = (XYChart) mChart;\r
147       return chart.toRealPoint(oldX, oldY, scale);\r
148     }\r
149     return null;\r
150   }\r
151 \r
152   @Override\r
153   protected void onDraw(Canvas canvas) {\r
154     super.onDraw(canvas);\r
155     canvas.getClipBounds(mRect);\r
156     int top = mRect.top;\r
157     int left = mRect.left;\r
158     int width = mRect.width();\r
159     int height = mRect.height();\r
160     if (mRenderer.isInScroll()) {\r
161       top = 0;\r
162       left = 0;\r
163       width = getMeasuredWidth();\r
164       height = getMeasuredHeight();\r
165     }\r
166     mChart.draw(canvas, left, top, width, height, mPaint);\r
167     if (mRenderer != null && mRenderer.isZoomEnabled() && mRenderer.isZoomButtonsVisible()) {\r
168       mPaint.setColor(ZOOM_BUTTONS_COLOR);\r
169       zoomSize = Math.max(zoomSize, Math.min(width, height) / 7);\r
170       mZoomR.set(left + width - zoomSize * 3, top + height - zoomSize * 0.775f, left + width, top\r
171           + height);\r
172       canvas.drawRoundRect(mZoomR, zoomSize / 3, zoomSize / 3, mPaint);\r
173       float buttonY = top + height - zoomSize * 0.625f;\r
174       canvas.drawBitmap(zoomInImage, left + width - zoomSize * 2.75f, buttonY, null);\r
175       canvas.drawBitmap(zoomOutImage, left + width - zoomSize * 1.75f, buttonY, null);\r
176       canvas.drawBitmap(fitZoomImage, left + width - zoomSize * 0.75f, buttonY, null);\r
177     }\r
178   }\r
179 \r
180   /**\r
181    * Sets the zoom rate.\r
182    * \r
183    * @param rate the zoom rate\r
184    */\r
185   public void setZoomRate(float rate) {\r
186     if (mZoomIn != null && mZoomOut != null) {\r
187       mZoomIn.setZoomRate(rate);\r
188       mZoomOut.setZoomRate(rate);\r
189     }\r
190   }\r
191 \r
192   /**\r
193    * Do a chart zoom in.\r
194    */\r
195   public void zoomIn() {\r
196     if (mZoomIn != null) {\r
197       mZoomIn.apply(Zoom.ZOOM_AXIS_XY);\r
198       repaint();\r
199     }\r
200   }\r
201 \r
202   /**\r
203    * Do a chart zoom out.\r
204    */\r
205   public void zoomOut() {\r
206     if (mZoomOut != null) {\r
207       mZoomOut.apply(Zoom.ZOOM_AXIS_XY);\r
208       repaint();\r
209     }\r
210   }\r
211   \r
212 \r
213 \r
214   /**\r
215    * Do a chart zoom reset / fit zoom.\r
216    */\r
217   public void zoomReset() {\r
218     if (mFitZoom != null) {\r
219       mFitZoom.apply();\r
220       mZoomIn.notifyZoomResetListeners();\r
221       repaint();\r
222     }\r
223   }\r
224 \r
225   /**\r
226    * Adds a new zoom listener.\r
227    * \r
228    * @param listener zoom listener\r
229    */\r
230   public void addZoomListener(ZoomListener listener, boolean onButtons, boolean onPinch) {\r
231     if (onButtons) {\r
232       if (mZoomIn != null) {\r
233         mZoomIn.addZoomListener(listener);\r
234         mZoomOut.addZoomListener(listener);\r
235       }\r
236       if (onPinch) {\r
237         mTouchHandler.addZoomListener(listener);\r
238       }\r
239     }\r
240   }\r
241 \r
242   /**\r
243    * Removes a zoom listener.\r
244    * \r
245    * @param listener zoom listener\r
246    */\r
247   public synchronized void removeZoomListener(ZoomListener listener) {\r
248     if (mZoomIn != null) {\r
249       mZoomIn.removeZoomListener(listener);\r
250       mZoomOut.removeZoomListener(listener);\r
251     }\r
252     mTouchHandler.removeZoomListener(listener);\r
253   }\r
254 \r
255   /**\r
256    * Adds a new pan listener.\r
257    * \r
258    * @param listener pan listener\r
259    */\r
260   public void addPanListener(PanListener listener) {\r
261     mTouchHandler.addPanListener(listener);\r
262   }\r
263 \r
264   /**\r
265    * Removes a pan listener.\r
266    * \r
267    * @param listener pan listener\r
268    */\r
269   public void removePanListener(PanListener listener) {\r
270     mTouchHandler.removePanListener(listener);\r
271   }\r
272 \r
273   protected RectF getZoomRectangle() {\r
274     return mZoomR;\r
275   }\r
276 \r
277   @Override\r
278   public boolean onTouchEvent(MotionEvent event) {\r
279     if (event.getAction() == MotionEvent.ACTION_DOWN) {\r
280       // save the x and y so they can be used in the click and long press\r
281       // listeners\r
282       oldX = event.getX();\r
283       oldY = event.getY();\r
284     }\r
285     if (mRenderer != null && (mRenderer.isPanEnabled() || mRenderer.isZoomEnabled())) {\r
286       if (mTouchHandler.handleTouch(event)) {\r
287         return true;\r
288       }\r
289     }\r
290     return super.onTouchEvent(event);\r
291   }\r
292 \r
293   /**\r
294    * Schedule a view content repaint.\r
295    */\r
296   public void repaint() {\r
297     mHandler.post(new Runnable() {\r
298       public void run() {\r
299         invalidate();\r
300       }\r
301     });\r
302   }\r
303 \r
304   /**\r
305    * Schedule a view content repaint, in the specified rectangle area.\r
306    * \r
307    * @param left the left position of the area to be repainted\r
308    * @param top the top position of the area to be repainted\r
309    * @param right the right position of the area to be repainted\r
310    * @param bottom the bottom position of the area to be repainted\r
311    */\r
312   public void repaint(final int left, final int top, final int right, final int bottom) {\r
313     mHandler.post(new Runnable() {\r
314       public void run() {\r
315         invalidate(left, top, right, bottom);\r
316       }\r
317     });\r
318   }\r
319 \r
320   /**\r
321    * Saves the content of the graphical view to a bitmap.\r
322    * \r
323    * @return the bitmap\r
324    */\r
325   public Bitmap toBitmap() {\r
326     setDrawingCacheEnabled(false);\r
327     if (!isDrawingCacheEnabled()) {\r
328       setDrawingCacheEnabled(true);\r
329     }\r
330     if (mRenderer.isApplyBackgroundColor()) {\r
331       setDrawingCacheBackgroundColor(mRenderer.getBackgroundColor());\r
332     }\r
333     setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);\r
334     return getDrawingCache(true);\r
335   }\r
336 \r
337 }