Advertisement
Guest User

Untitled

a guest
Oct 9th, 2014
448
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.25 KB | None | 0 0
  1. /**
  2. * PhotoSorterView.java
  3. *
  4. * (c) Luke Hutchison ([email protected])
  5. *
  6. * TODO: Add OpenGL acceleration.
  7. *
  8. * --
  9. *
  10. * Released under the MIT license (but please notify me if you use this code, so that I can give your project credit at
  11. * http://code.google.com/p/android-multitouch-controller ).
  12. *
  13. * MIT license: http://www.opensource.org/licenses/MIT
  14. *
  15. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
  16. * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  17. * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  18. *
  19. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. */
  26. package org.metalev.multitouch.photosortr;
  27.  
  28. import java.util.ArrayList;
  29.  
  30. import org.metalev.multitouch.controller.MultiTouchController;
  31. import org.metalev.multitouch.controller.MultiTouchController.MultiTouchObjectCanvas;
  32. import org.metalev.multitouch.controller.MultiTouchController.PointInfo;
  33. import org.metalev.multitouch.controller.MultiTouchController.PositionAndScale;
  34.  
  35. import android.content.Context;
  36. import android.content.res.Configuration;
  37. import android.content.res.Resources;
  38. import android.graphics.Bitmap;
  39. import android.graphics.BitmapFactory;
  40. import android.graphics.Canvas;
  41. import android.graphics.Color;
  42. import android.graphics.drawable.Drawable;
  43. import android.util.AttributeSet;
  44. import android.util.DisplayMetrics;
  45. import android.view.MotionEvent;
  46. import android.view.View;
  47.  
  48. public class PhotoSortrView extends View implements MultiTouchObjectCanvas<PhotoSortrView.Img> {
  49.  
  50. private static final int[] IMAGES = { R.drawable.ovalwhite, R.drawable.ovalgreen, R.drawable.ovalred, R.drawable.eclipsewhite, R.drawable.eclipsegreen ,R.drawable.eclipsered ,R.drawable.rectanglewhite ,R.drawable.rectanglegreen ,R.drawable.rectanglered ,R.drawable.squarewhite,R.drawable.squaregreen,R.drawable.squarered };
  51.  
  52. private ArrayList<Img> mImages = new ArrayList<Img>();
  53.  
  54. // --
  55.  
  56. private MultiTouchController<Img> multiTouchController = new MultiTouchController<Img>(this);
  57.  
  58. // --
  59.  
  60. private PointInfo currTouchPoint = new PointInfo();
  61.  
  62. private boolean mShowDebugInfo = true;
  63.  
  64. private static final int UI_MODE_ROTATE = 1, UI_MODE_ANISOTROPIC_SCALE = 2;
  65.  
  66. private int mUIMode = UI_MODE_ROTATE;
  67.  
  68. // --
  69.  
  70. //private Paint mLinePaintTouchPointCircle = new Paint();
  71.  
  72. // ---------------------------------------------------------------------------------------------------
  73.  
  74. public PhotoSortrView(Context context) {
  75. this(context, null);
  76. }
  77.  
  78. public PhotoSortrView(Context context, AttributeSet attrs) {
  79. this(context, attrs, 0);
  80. }
  81.  
  82. public PhotoSortrView(Context context, AttributeSet attrs, int defStyle) {
  83. super(context, attrs, defStyle);
  84. init(context);
  85. }
  86.  
  87. private void init(Context context) {
  88. Resources res = context.getResources();
  89. for (int i = 0; i < IMAGES.length; i++)
  90. mImages.add(new Img(IMAGES[i], res));
  91.  
  92. /*mLinePaintTouchPointCircle.setColor(Color.YELLOW);
  93. mLinePaintTouchPointCircle.setStrokeWidth(5);
  94. mLinePaintTouchPointCircle.setStyle(Style.STROKE);
  95. mLinePaintTouchPointCircle.setAntiAlias(true);*/
  96. setBackgroundColor(Color.BLACK);
  97. }
  98.  
  99. /** Called by activity's onResume() method to load the images */
  100. public void loadImages(Context context) {
  101. Resources res = context.getResources();
  102. int n = mImages.size();
  103. for (int i = 0; i < n; i++)
  104. mImages.get(i).load(res);
  105. }
  106.  
  107. /** Called by activity's onPause() method to free memory used for loading the images */
  108. public void unloadImages() {
  109. int n = mImages.size();
  110. for (int i = 0; i < n; i++)
  111. mImages.get(i).unload();
  112. }
  113.  
  114. // ---------------------------------------------------------------------------------------------------
  115.  
  116. @Override
  117. protected void onDraw(Canvas canvas) {
  118. super.onDraw(canvas);
  119. Bitmap bacBitmap = BitmapFactory.decodeResource(getResources(),
  120. R.drawable.lake);
  121. canvas.drawBitmap(bacBitmap, 10, 0, null);
  122. int n = mImages.size();
  123. for (int i = 0; i < n; i++)
  124. mImages.get(i).draw(canvas);
  125. /*if (mShowDebugInfo)
  126. drawMultitouchDebugMarks(canvas);*/
  127. }
  128.  
  129. // ---------------------------------------------------------------------------------------------------
  130.  
  131. public void trackballClicked() {
  132. mUIMode = (mUIMode + 1) % 3;
  133. invalidate();
  134. }
  135.  
  136. private void drawMultitouchDebugMarks(Canvas canvas) {
  137. if (currTouchPoint.isDown()) {
  138. float[] xs = currTouchPoint.getXs();
  139. float[] ys = currTouchPoint.getYs();
  140. float[] pressures = currTouchPoint.getPressures();
  141. int numPoints = Math.min(currTouchPoint.getNumTouchPoints(), 2);
  142. /*for (int i = 0; i < numPoints; i++)
  143. canvas.drawCircle(xs[i], ys[i], 50 + pressures[i] * 80, mLinePaintTouchPointCircle);
  144. if (numPoints == 2)
  145. canvas.drawLine(xs[0], ys[0], xs[1], ys[1], mLinePaintTouchPointCircle);*/
  146. }
  147. }
  148.  
  149. // ---------------------------------------------------------------------------------------------------
  150.  
  151. /** Pass touch events to the MT controller */
  152. @Override
  153. public boolean onTouchEvent(MotionEvent event) {
  154. return multiTouchController.onTouchEvent(event);
  155. }
  156.  
  157. /** Get the image that is under the single-touch point, or return null (canceling the drag op) if none */
  158. public Img getDraggableObjectAtPoint(PointInfo pt) {
  159. float x = pt.getX(), y = pt.getY();
  160. int n = mImages.size();
  161. for (int i = n - 1; i >= 0; i--) {
  162. Img im = mImages.get(i);
  163. if (im.containsPoint(x, y))
  164. return im;
  165. }
  166. return null;
  167. }
  168.  
  169. /**
  170. * Select an object for dragging. Called whenever an object is found to be under the point (non-null is returned by getDraggableObjectAtPoint())
  171. * and a drag operation is starting. Called with null when drag op ends.
  172. */
  173.  
  174. public void selectObject(Img img, PointInfo touchPoint) {
  175. currTouchPoint.set(touchPoint);
  176. if (img != null) {
  177. // Move image to the top of the stack when selected
  178. mImages.remove(img);
  179. mImages.add(img);
  180. } else {
  181. // Called with img == null when drag stops.
  182. }
  183. invalidate();
  184. }
  185.  
  186. /** Get the current position and scale of the selected image. Called whenever a drag starts or is reset. */
  187. public void getPositionAndScale(Img img, PositionAndScale objPosAndScaleOut) {
  188. // FIXME affine-izem (and fix the fact that the anisotropic_scale part requires averaging the two scale factors)
  189. objPosAndScaleOut.set(img.getCenterX(), img.getCenterY(), (mUIMode & UI_MODE_ANISOTROPIC_SCALE) == 0,
  190. (img.getScaleX() + img.getScaleY()) / 2, (mUIMode & UI_MODE_ANISOTROPIC_SCALE) != 0, img.getScaleX(), img.getScaleY(),
  191. (mUIMode & UI_MODE_ROTATE) != 0, img.getAngle());
  192. }
  193.  
  194. /** Set the position and scale of the dragged/stretched image. */
  195. public boolean setPositionAndScale(Img img, PositionAndScale newImgPosAndScale, PointInfo touchPoint) {
  196. currTouchPoint.set(touchPoint);
  197. boolean ok = img.setPos(newImgPosAndScale);
  198. if (ok)
  199. invalidate();
  200. return ok;
  201. }
  202.  
  203. // ----------------------------------------------------------------------------------------------
  204.  
  205. class Img {
  206. private int resId;
  207.  
  208. private Drawable drawable;
  209.  
  210. private boolean firstLoad;
  211.  
  212. private int width, height, displayWidth, displayHeight;
  213.  
  214. private float centerX, centerY, scaleX, scaleY, angle;
  215.  
  216. private float minX, maxX, minY, maxY;
  217.  
  218. private static final float SCREEN_MARGIN = 100;
  219.  
  220. public Img(int resId, Resources res) {
  221. this.resId = resId;
  222. this.firstLoad = true;
  223. getMetrics(res);
  224. }
  225.  
  226. private void getMetrics(Resources res) {
  227. DisplayMetrics metrics = res.getDisplayMetrics();
  228. // The DisplayMetrics don't seem to always be updated on screen rotate, so we hard code a portrait
  229. // screen orientation for the non-rotated screen here...
  230. // this.displayWidth = metrics.widthPixels;
  231. // this.displayHeight = metrics.heightPixels;
  232. this.displayWidth = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? Math.max(metrics.widthPixels,
  233. metrics.heightPixels) : Math.min(metrics.widthPixels, metrics.heightPixels);
  234. this.displayHeight = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? Math.min(metrics.widthPixels,
  235. metrics.heightPixels) : Math.max(metrics.widthPixels, metrics.heightPixels);
  236. }
  237.  
  238. /** Called by activity's onResume() method to load the images */
  239. public void load(Resources res) {
  240. getMetrics(res);
  241. this.drawable = res.getDrawable(resId);
  242. this.width = drawable.getIntrinsicWidth();
  243. this.height = drawable.getIntrinsicHeight();
  244. float cx, cy, sx, sy;
  245. if (firstLoad) {
  246. cx = SCREEN_MARGIN + (float) (Math.random() * (displayWidth - 2 * SCREEN_MARGIN));
  247. cy = SCREEN_MARGIN + (float) (Math.random() * (displayHeight - 2 * SCREEN_MARGIN));
  248. float sc = (float) (Math.max(displayWidth, displayHeight) / (float) Math.max(width, height) * Math.random() * 0.3 + 0.2);
  249. sx = sy = sc;
  250. firstLoad = false;
  251. } else {
  252. // Reuse position and scale information if it is available
  253. // FIXME this doesn't actually work because the whole activity is torn down and re-created on rotate
  254. cx = this.centerX;
  255. cy = this.centerY;
  256. sx = this.scaleX;
  257. sy = this.scaleY;
  258. // Make sure the image is not off the screen after a screen rotation
  259. if (this.maxX < SCREEN_MARGIN)
  260. cx = SCREEN_MARGIN;
  261. else if (this.minX > displayWidth - SCREEN_MARGIN)
  262. cx = displayWidth - SCREEN_MARGIN;
  263. if (this.maxY > SCREEN_MARGIN)
  264. cy = SCREEN_MARGIN;
  265. else if (this.minY > displayHeight - SCREEN_MARGIN)
  266. cy = displayHeight - SCREEN_MARGIN;
  267. }
  268. setPos(cx, cy, sx, sy, 0.0f);
  269. }
  270.  
  271. /** Called by activity's onPause() method to free memory used for loading the images */
  272. public void unload() {
  273. this.drawable = null;
  274. }
  275.  
  276. /** Set the position and scale of an image in screen coordinates */
  277. public boolean setPos(PositionAndScale newImgPosAndScale) {
  278. return setPos(newImgPosAndScale.getXOff(), newImgPosAndScale.getYOff(), (mUIMode & UI_MODE_ANISOTROPIC_SCALE) != 0 ? newImgPosAndScale
  279. .getScaleX() : newImgPosAndScale.getScale(), (mUIMode & UI_MODE_ANISOTROPIC_SCALE) != 0 ? newImgPosAndScale.getScaleY()
  280. : newImgPosAndScale.getScale(), newImgPosAndScale.getAngle());
  281. // FIXME: anisotropic scaling jumps when axis-snapping
  282. // FIXME: affine-ize
  283. // return setPos(newImgPosAndScale.getXOff(), newImgPosAndScale.getYOff(), newImgPosAndScale.getScaleAnisotropicX(),
  284. // newImgPosAndScale.getScaleAnisotropicY(), 0.0f);
  285. }
  286.  
  287. /** Set the position and scale of an image in screen coordinates */
  288. private boolean setPos(float centerX, float centerY, float scaleX, float scaleY, float angle) {
  289. float ws = (width / 2) * scaleX, hs = (height / 2) * scaleY;
  290. float newMinX = centerX - ws, newMinY = centerY - hs, newMaxX = centerX + ws, newMaxY = centerY + hs;
  291. if (newMinX > displayWidth - SCREEN_MARGIN || newMaxX < SCREEN_MARGIN || newMinY > displayHeight - SCREEN_MARGIN
  292. || newMaxY < SCREEN_MARGIN)
  293. return false;
  294. this.centerX = centerX;
  295. this.centerY = centerY;
  296. this.scaleX = scaleX;
  297. this.scaleY = scaleY;
  298. this.angle = angle;
  299. this.minX = newMinX;
  300. this.minY = newMinY;
  301. this.maxX = newMaxX;
  302. this.maxY = newMaxY;
  303. return true;
  304. }
  305.  
  306. /** Return whether or not the given screen coords are inside this image */
  307. public boolean containsPoint(float scrnX, float scrnY) {
  308. // FIXME: need to correctly account for image rotation
  309. return (scrnX >= minX && scrnX <= maxX && scrnY >= minY && scrnY <= maxY);
  310. }
  311.  
  312. public void draw(Canvas canvas) {
  313. canvas.save();
  314. float dx = (maxX + minX) / 2;
  315. float dy = (maxY + minY) / 2;
  316. drawable.setBounds((int) minX, (int) minY, (int) maxX, (int) maxY);
  317. //drawable.setBounds(50, 50, 50, 50);
  318. canvas.translate(dx, dy);
  319. canvas.rotate(angle * 180.0f / (float) Math.PI);
  320. canvas.translate(-dx, -dy);
  321. drawable.draw(canvas);
  322. canvas.restore();
  323. }
  324.  
  325. public Drawable getDrawable() {
  326. return drawable;
  327. }
  328.  
  329. public int getWidth() {
  330. return width;
  331. }
  332.  
  333. public int getHeight() {
  334. return height;
  335. }
  336.  
  337. public float getCenterX() {
  338. return centerX;
  339. }
  340.  
  341. public float getCenterY() {
  342. return centerY;
  343. }
  344.  
  345. public float getScaleX() {
  346. return scaleX;
  347. }
  348.  
  349. public float getScaleY() {
  350. return scaleY;
  351. }
  352.  
  353. public float getAngle() {
  354. return angle;
  355. }
  356.  
  357. // FIXME: these need to be updated for rotation
  358. public float getMinX() {
  359. return minX;
  360. }
  361.  
  362. public float getMaxX() {
  363. return maxX;
  364. }
  365.  
  366. public float getMinY() {
  367. return minY;
  368. }
  369.  
  370. public float getMaxY() {
  371. return maxY;
  372. }
  373. }
  374. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement