Many style and navigation changes. Pulled in ActionBarCompat from Android sample...
[debian/openrocket] / android / src / net / sf / openrocket / android / motor / BurnPlotFragment.java
1 package net.sf.openrocket.android.motor;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.List;\r
5 import java.util.Vector;\r
6 \r
7 import net.sf.openrocket.R;\r
8 import net.sf.openrocket.android.db.DbAdapter;\r
9 import net.sf.openrocket.android.util.AndroidLogWrapper;\r
10 import android.graphics.Color;\r
11 import android.graphics.Paint;\r
12 import android.graphics.PointF;\r
13 import android.os.Bundle;\r
14 import android.support.v4.app.Fragment;\r
15 import android.view.LayoutInflater;\r
16 import android.view.MotionEvent;\r
17 import android.view.ScaleGestureDetector;\r
18 import android.view.View;\r
19 import android.view.View.OnTouchListener;\r
20 import android.view.ViewGroup;\r
21 \r
22 import com.androidplot.xy.BoundaryMode;\r
23 import com.androidplot.xy.LineAndPointFormatter;\r
24 import com.androidplot.xy.LineAndPointRenderer;\r
25 import com.androidplot.xy.SimpleXYSeries;\r
26 import com.androidplot.xy.XYPlot;\r
27 import com.androidplot.xy.YValueMarker;\r
28 \r
29 public class BurnPlotFragment extends Fragment implements OnTouchListener {\r
30 \r
31         private ExtendedThrustCurveMotor motor;\r
32         private long motorId;\r
33 \r
34         private XYPlot mySimpleXYPlot;\r
35         private SimpleXYSeries mySeries;\r
36         private PointF minXY;\r
37         private PointF maxXY;\r
38 \r
39         private float absMinX;\r
40         private float absMaxX;\r
41 \r
42         private ScaleGestureDetector mScaleDetector;\r
43         private float mScaleFactor = 1.f;\r
44 \r
45         public static BurnPlotFragment newInstance( long motorId ) {\r
46                 BurnPlotFragment frag = new BurnPlotFragment();\r
47                 Bundle bundle = new Bundle();\r
48                 bundle.putLong("motorId", motorId);\r
49                 frag.setArguments(bundle);\r
50                 return frag;\r
51         }\r
52 \r
53         @Override\r
54         public void onCreate(Bundle savedInstanceState) {\r
55                 AndroidLogWrapper.d(BurnPlotFragment.class,"onCreate");\r
56 \r
57                 if ( savedInstanceState!= null) {\r
58                         motorId = savedInstanceState.getLong("motorId",-1);\r
59                 } else {\r
60                         Bundle b = getArguments();\r
61                         motorId = b.getLong("motorId");\r
62                 }\r
63 \r
64                 DbAdapter mDbHelper = new DbAdapter(getActivity());\r
65                 mDbHelper.open();\r
66 \r
67                 try {\r
68                         motor = mDbHelper.getMotorDao().fetchMotor(motorId);\r
69                 } catch ( Exception e ) {\r
70 \r
71                 }\r
72 \r
73                 mDbHelper.close();\r
74                 super.onCreate(savedInstanceState);\r
75         }\r
76 \r
77         @Override\r
78         public void onSaveInstanceState(Bundle outState) {\r
79                 super.onSaveInstanceState(outState);\r
80                 outState.putLong("motorId", motorId);\r
81         }\r
82 \r
83         @Override\r
84         public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
85                         Bundle savedInstanceState) {\r
86                 AndroidLogWrapper.d(BurnPlotFragment.class,"onCreateView");\r
87                 View v = inflater.inflate(R.layout.motor_burn, container, false);\r
88                 mySimpleXYPlot = (XYPlot) v.findViewById(R.id.xyplot);\r
89                 mySimpleXYPlot.setOnTouchListener(this);\r
90                 mScaleDetector = new ScaleGestureDetector(v.getContext(), new ScaleListener());\r
91                 init(motor);\r
92                 return v;\r
93         }\r
94 \r
95         private static List<Double> fromArray( double[] arry ) {\r
96                 List<Double> l = new ArrayList<Double>(arry.length);\r
97                 for( double d: arry ) {\r
98                         l.add(d);\r
99                 }\r
100                 return l;\r
101         }\r
102 \r
103         private void init( ExtendedThrustCurveMotor motor ) {\r
104 \r
105                 mySimpleXYPlot.setUserDomainOrigin(0);\r
106                 mySimpleXYPlot.setUserRangeOrigin(0);\r
107                 mySimpleXYPlot.setRangeLabel("impuse (n)");\r
108                 mySimpleXYPlot.setDomainLabel("time (s)");\r
109                 YValueMarker average = new YValueMarker(motor.getThrustCurveMotor().getAverageThrustEstimate(),"average" );\r
110                 average.getLinePaint().setColor(Color.BLACK);\r
111                 average.getTextPaint().setColor(Color.BLACK);\r
112                 mySimpleXYPlot.addMarker( average );\r
113                 mySimpleXYPlot.disableAllMarkup();\r
114 \r
115                 try {\r
116                         mySeries = new SimpleXYSeries( \r
117                                         fromArray(motor.getThrustCurveMotor().getTimePoints()),\r
118                                         fromArray(motor.getThrustCurveMotor().getThrustPoints()), \r
119                                         motor.getThrustCurveMotor().getManufacturer().getDisplayName() + " " + motor.getThrustCurveMotor().getDesignation()\r
120                                         );\r
121                 } catch ( Exception ex ) {\r
122 \r
123                         Vector<Double> data = new Vector<Double>();\r
124                         data.add(0.0);\r
125                         data.add(0.0);\r
126                         data.add(1.0);\r
127                         data.add(1.0);\r
128                         mySeries = new SimpleXYSeries(data, SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED,"no data");\r
129                 }\r
130 \r
131                 LineAndPointFormatter formatter= new LineAndPointFormatter(Color.RED, Color.GREEN, Color.GREEN);\r
132 \r
133                 formatter.getLinePaint().setShadowLayer(0, 0, 0, 0);\r
134                 formatter.getVertexPaint().setShadowLayer(0, 0, 0, 0);\r
135                 mySimpleXYPlot.addSeries(mySeries, LineAndPointRenderer.class,formatter);\r
136 \r
137                 //Set of internal variables for keeping track of the boundaries\r
138                 mySimpleXYPlot.calculateMinMaxVals();\r
139 \r
140                 mySimpleXYPlot.redraw();\r
141 \r
142                 minXY=new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),mySimpleXYPlot.getCalculatedMinY().floatValue());\r
143                 maxXY=new PointF(mySimpleXYPlot.getCalculatedMaxX().floatValue(),mySimpleXYPlot.getCalculatedMaxY().floatValue());\r
144 \r
145                 absMinX = minXY.x;\r
146                 absMaxX = maxXY.x;\r
147 \r
148         }\r
149 \r
150         private float mPosX;\r
151         private float mPosY;\r
152 \r
153         private float mLastTouchX;\r
154         private float mLastTouchY;\r
155 \r
156         private int mActivePointerId = -1;\r
157 \r
158         @Override\r
159         public boolean onTouch(View arg0, MotionEvent event) {\r
160                 mScaleDetector.onTouchEvent(event);\r
161 \r
162                 final int action = event.getAction();\r
163                 switch ( action & MotionEvent.ACTION_MASK ) {\r
164                 case MotionEvent.ACTION_DOWN: {\r
165                         final float x = event.getX();\r
166                         final float y = event.getY();\r
167 \r
168                         mLastTouchX = x;\r
169                         mLastTouchY = y;\r
170 \r
171                         mActivePointerId = event.getPointerId(0);\r
172                         break;\r
173                 }\r
174 \r
175                 case MotionEvent.ACTION_MOVE: {\r
176                         final int pointerIndex = event.findPointerIndex(mActivePointerId);\r
177                         final float x = event.getX(pointerIndex);\r
178                         final float y = event.getY(pointerIndex);\r
179 \r
180                         if (!mScaleDetector.isInProgress()) {\r
181                                 final float dx = x - mLastTouchX;\r
182                                 final float dy = y - mLastTouchY;\r
183 \r
184                                 mPosX += dx;\r
185                                 mPosY += dy;\r
186                                 scroll(dx);\r
187                                 // do scroll.\r
188 \r
189                         }\r
190                         mLastTouchX = x;\r
191                         mLastTouchY = y;\r
192 \r
193                         break;\r
194                 }\r
195 \r
196                 case MotionEvent.ACTION_UP: {\r
197                         mActivePointerId = -1;\r
198                         break;\r
199                 }\r
200 \r
201                 case MotionEvent.ACTION_CANCEL: {\r
202                         mActivePointerId = -1;\r
203                         break;\r
204                 }\r
205 \r
206                 case MotionEvent.ACTION_POINTER_UP: {\r
207                         final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;\r
208                         final int pointerId = event.getPointerId(pointerIndex);\r
209                         if (pointerId == mActivePointerId) {\r
210                                 // This was our active pointer going up.  choose a new active pointer and adjust accordingly.\r
211                                 final int newPointerIndex = pointerIndex ==0 ? 1:0;\r
212                                 mLastTouchX = event.getX(newPointerIndex);\r
213                                 mLastTouchY = event.getY(newPointerIndex);\r
214                                 mActivePointerId = event.getPointerId(newPointerIndex);\r
215                         }\r
216                         break;\r
217                 }\r
218                 }       \r
219                 return true;\r
220         }\r
221 \r
222         private void zoom(float scale) {\r
223                 AndroidLogWrapper.d(BurnPlotFragment.class,"zoom by " + scale);\r
224                 float domainSpan = absMaxX      - absMinX;\r
225                 AndroidLogWrapper.d(BurnPlotFragment.class,"domainSpan = " + domainSpan);\r
226                 float domainMidPoint = absMaxX          - domainSpan / 2.0f;\r
227                 AndroidLogWrapper.d(BurnPlotFragment.class,"domainMidPoint = " + domainMidPoint);\r
228                 float offset = domainSpan / scale;\r
229                 AndroidLogWrapper.d(BurnPlotFragment.class,"offset " + offset);\r
230                 minXY.x=domainMidPoint- offset;\r
231                 AndroidLogWrapper.d(BurnPlotFragment.class,"min X " + minXY.x);\r
232                 maxXY.x=domainMidPoint+offset;\r
233                 AndroidLogWrapper.d(BurnPlotFragment.class,"max X " + maxXY.x);\r
234                 checkBoundaries();\r
235                 mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);\r
236                 mySimpleXYPlot.redraw();\r
237         }\r
238 \r
239         private void scroll(float pan) {\r
240                 float domainSpan = maxXY.x      - minXY.x;\r
241                 float step = domainSpan / mySimpleXYPlot.getWidth();\r
242                 float offset = pan * step;\r
243                 minXY.x+= offset;\r
244                 maxXY.x+= offset;\r
245                 checkBoundaries();\r
246                 mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);\r
247                 mySimpleXYPlot.redraw();\r
248         }\r
249 \r
250         private void checkBoundaries() {\r
251 \r
252                 if ( minXY.x < absMinX) \r
253                         minXY.x = absMinX;\r
254                 //              else if ( minXY.x > maxNoError )\r
255                 //                      minXY.x = maxNoError;\r
256 \r
257                 if ( maxXY.x > absMaxX)\r
258                         maxXY.x = absMaxX;\r
259                 //              else if ( maxXY.x < minNoError)\r
260                 //                      maxXY.x = minNoError;\r
261         }\r
262         private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {\r
263                 @Override\r
264                 public boolean onScale( ScaleGestureDetector detector ) {\r
265                         mScaleFactor *= detector.getScaleFactor();\r
266 \r
267                         mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 5.0f));\r
268                         zoom(mScaleFactor);\r
269                         return true;\r
270                 }\r
271         }\r
272 }\r
273 \r