1 package jp.sourceforge.gokigen.memoma.drawers;
3 import java.util.Enumeration;
4 import android.content.SharedPreferences;
5 import android.graphics.Bitmap;
6 import android.graphics.BitmapFactory;
7 import android.graphics.Canvas;
8 import android.graphics.Color;
9 import android.graphics.DashPathEffect;
10 import android.graphics.Paint;
11 import android.graphics.Path;
12 import android.graphics.RectF;
13 import android.preference.PreferenceManager;
14 import android.util.Log;
15 import android.view.MotionEvent;
16 import android.view.GestureDetector;
17 import android.view.ScaleGestureDetector;
18 import android.widget.SeekBar;
19 import android.widget.TextView;
21 import androidx.appcompat.app.AppCompatActivity;
23 import jp.sourceforge.gokigen.memoma.holders.ObjectConnector;
24 import jp.sourceforge.gokigen.memoma.holders.PositionObject;
25 import jp.sourceforge.gokigen.memoma.operations.IObjectSelectionReceiver;
26 import jp.sourceforge.gokigen.memoma.io.ImageLoader;
27 import jp.sourceforge.gokigen.memoma.R;
28 import jp.sourceforge.gokigen.memoma.holders.LineStyleHolder;
29 import jp.sourceforge.gokigen.memoma.holders.MeMoMaConnectLineHolder;
30 import jp.sourceforge.gokigen.memoma.holders.MeMoMaObjectHolder;
31 import jp.sourceforge.gokigen.memoma.holders.OperationModeHolder;
39 public class MeMoMaCanvasDrawer implements ICanvasDrawer, GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener, SeekBar.OnSeekBarChangeListener
41 private final String TAG = toString();
43 public static final float OBJECTLABEL_MARGIN = 8.0f;
44 public static final float OBJECTLABEL_MARGIN_WIDTH = 24.0f;
46 public static final int BACKGROUND_COLOR_DEFAULT = 0xff004000;
47 private int backgroundColor = BACKGROUND_COLOR_DEFAULT;
49 private PositionObject selectedPosition = null;
50 private float tempPosX = Float.MIN_VALUE;
51 private float tempPosY = Float.MIN_VALUE;
52 private float downPosX = Float.MIN_VALUE;
53 private float downPosY = Float.MIN_VALUE;
55 // 以下の値は、MeMoMaListenerで初期値を設定する
56 private int objectStyle = MeMoMaObjectHolder.DRAWSTYLE_RECTANGLE;
58 private final LineStyleHolder lineStyleHolder;
60 private float drawScale = 1.0f; // 表示の倍率
61 private float drawTransX = 0.0f; // 並行移動距離 (X)
62 private float drawTransY = 0.0f; // 並行移動距離 (Y)
63 private boolean onScaling = false; // ピンチイン・ピンチアウト操作しているかどうかを示す
64 private int currentScaleBar= 50; // 現在のピンチイン・ピンチアウト倍率
66 private boolean onGestureProcessed = false; // 長押し時の処理を行なっているかどうかを示す。
68 private float screenWidth = 0.0f; // 表示領域の幅
69 private float screenHeight = 0.0f; // 表示領域の高さ
71 private int displayObjectInformation = 1; // オブジェクトラベルの表示
73 private String backgroundBitmapUri = null;
74 private Bitmap backgroundBitmap = null;
76 private final MeMoMaObjectHolder objectHolder;
77 private final MeMoMaConnectLineHolder lineHolder;
78 private final IObjectSelectionReceiver selectionReceiver;
80 private final GestureDetector gestureDetector;
81 private final ScaleGestureDetector scaleGestureDetector;
83 private final AppCompatActivity parent;
89 public MeMoMaCanvasDrawer(AppCompatActivity argument, MeMoMaObjectHolder object, LineStyleHolder styleHolder, IObjectSelectionReceiver receiver)
91 objectHolder = object;
92 lineHolder = objectHolder.getConnectLineHolder();
93 selectionReceiver = receiver;
94 lineStyleHolder = styleHolder;
98 gestureDetector = new GestureDetector(argument, this);
99 scaleGestureDetector = new ScaleGestureDetector(argument, this);
102 restoreTranslateAndZoomScale();
107 * (ここで指定された形状のチェックを行っておく。)
111 public void setObjectStyle(int style)
115 case MeMoMaObjectHolder.DRAWSTYLE_OVAL:
116 case MeMoMaObjectHolder.DRAWSTYLE_ROUNDRECT:
117 case MeMoMaObjectHolder.DRAWSTYLE_RECTANGLE:
118 case MeMoMaObjectHolder.DRAWSTYLE_DIAMOND:
119 case MeMoMaObjectHolder.DRAWSTYLE_KEYBOARD:
120 case MeMoMaObjectHolder.DRAWSTYLE_PAPER:
121 case MeMoMaObjectHolder.DRAWSTYLE_DRUM:
122 case MeMoMaObjectHolder.DRAWSTYLE_PARALLELOGRAM:
123 case MeMoMaObjectHolder.DRAWSTYLE_HEXAGONAL:
124 case MeMoMaObjectHolder.DRAWSTYLE_CIRCLE:
125 case MeMoMaObjectHolder.DRAWSTYLE_NO_REGION:
126 case MeMoMaObjectHolder.DRAWSTYLE_LOOP_START:
127 case MeMoMaObjectHolder.DRAWSTYLE_LOOP_END:
128 case MeMoMaObjectHolder.DRAWSTYLE_LEFT_ARROW:
129 case MeMoMaObjectHolder.DRAWSTYLE_DOWN_ARROW:
130 case MeMoMaObjectHolder.DRAWSTYLE_UP_ARROW:
131 case MeMoMaObjectHolder.DRAWSTYLE_RIGHT_ARROW:
136 objectStyle = MeMoMaObjectHolder.DRAWSTYLE_RECTANGLE;
145 public void updateBackgroundBitmap(String uri, int width, int height)
148 backgroundBitmapUri = uri;
150 // とりあえず、背景画像をクリアしてガベコレする。
151 backgroundBitmap = null;
155 // 背景画像の指定がなかったので、ここでリターンする。
160 // とりあえず設定する情報をログに残してみる
161 Log.v(TAG, "MeMoMaCanvasDrawer::updateBackgroundBitmap() : w:" + width + " , h:"+ height + " " + uri);
164 backgroundBitmap = ImageLoader.getBitmapFromUri(parent, ImageLoader.parseUri(uri), width, height);
168 Log.v(TAG, "MeMoMaCanvasDrawer::updateBackgroundBitmap() : " + uri + " , "+ ex.toString());
169 ex.printStackTrace();
170 backgroundBitmap = null;
171 backgroundBitmapUri = "";
181 public void setBackgroundUri(String uri)
183 backgroundBitmapUri = uri;
191 public void setBackgroundColor(String colorString)
195 backgroundColor = Color.parseColor(colorString);
201 //Log.v(Main.APP_IDENTIFIER, "Ex:" + ex.toString() + " " + ex.getMessage());
203 backgroundColor = BACKGROUND_COLOR_DEFAULT;
210 public void prepareToStart(int width, int height)
212 Log.v(TAG, "MeMoMaCanvasDrawer::prepareToStart() " + "x:" + width + " , " + "y:" + height);
215 //updateBackgroundBitmap(backgroundBitmapUri, width, height);
218 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
219 displayObjectInformation = Integer.parseInt(preferences.getString("objectPrintData", "1"));
223 * 画面の大きさが変わってしまった場合...
226 public void changedScreenProperty(int format, int width, int height)
229 updateBackgroundBitmap(backgroundBitmapUri, width, height);
233 screenHeight = height;
235 Log.v(TAG, "changedScreenProperty() " + "x:" + width + " , " + "y:" + height);
240 * キャンバスにオブジェクト(と接続線)を表示する
243 public void drawOnCanvas(Canvas canvas)
245 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::drawOnCanvas()");
249 //canvas.drawColor(Color.argb(backgroundColorAlfa, backgroundColorRed, backgroundColorGreen, backgroundColorBlue), Mode.CLEAR);
250 canvas.drawColor(backgroundColor);
252 // 背景画像が設定されていた場合は、背景画像を描画する
253 if (backgroundBitmap != null)
255 canvas.drawBitmap(backgroundBitmap, 0, 0, new Paint());
259 canvas.translate(drawTransX, drawTransY);
262 canvas.scale(drawScale, drawScale);
264 // オブジェクト間の接続線をすべて表示する
265 drawConnectionLines(canvas, 0.0f, 0.0f);
268 drawObjects(canvas, 0.0f, 0.0f);
271 if (isFlicking(canvas))
273 // 移動中の場合、フリック時の軌跡と現在位置を表示する
274 drawTrackAndPositions(canvas);
279 // 例外発生...でもそのときには何もしない
280 Log.v(TAG, "drawOnCanvas() ex: " + ex.getMessage());
285 * オブジェクトをBitmapCanvas上に描く
288 public void drawOnBitmapCanvas(Canvas canvas, float offsetX, float offsetY)
292 Paint paint = new Paint();
295 canvas.drawColor(backgroundColor);
297 // 背景画像が設定されていた場合は、背景画像を描画する
298 if (backgroundBitmap != null)
300 canvas.drawBitmap(backgroundBitmap, offsetX, offsetY, paint);
303 // オブジェクト間の接続線をすべて表示する
304 drawConnectionLines(canvas, offsetX, offsetY);
307 drawObjects(canvas, offsetX, offsetY);
309 // タイトルとめもまのアイコンを表示する : 文字の色は黒でいいのかな...
310 Bitmap bitmap = BitmapFactory.decodeResource(parent.getResources(), R.drawable.icon1);
311 canvas.drawBitmap(bitmap, 2.0f, 2.0f, paint);
313 // 文字をライトグレー、ちょっと影付きにする
314 paint.setColor(Color.LTGRAY);
315 paint.setStyle(Paint.Style.FILL_AND_STROKE);
316 paint.setShadowLayer(0.5f, 0.5f, 0.5f, Color.DKGRAY);
318 canvas.drawText(objectHolder.getDataTitle(), (bitmap.getWidth() + 10.0f), 32.0f, paint);
323 // 例外発生...でもそのときには何もしない
324 Log.v(TAG, "drawOnBitmapCanvas() ex: " + ex.toString() + " " + ex.getMessage());
333 private void drawConnectionLines(Canvas canvas, float offsetX, float offsetY)
335 // オブジェクトの色と枠線を設定する (連続線用)
336 Paint paint = new Paint();
337 paint.setColor(Color.WHITE);
338 paint.setStyle(Paint.Style.STROKE);
340 // オブジェクトの色と枠線を設定する (点線用)
341 Paint dashLinePaint = new Paint();
342 dashLinePaint.setColor(Color.WHITE);
343 dashLinePaint.setStyle(Paint.Style.STROKE);
344 dashLinePaint.setPathEffect(new DashPathEffect(new float[]{ 5.0f, 5.0f }, 0));
346 // オブジェクトの描画 (保持しているものはすべて表示する)
347 Enumeration<Integer> keys = lineHolder.getLineKeys();
348 while (keys.hasMoreElements())
350 Integer key = keys.nextElement();
351 ObjectConnector line = lineHolder.getLine(key);
352 if (line.getKey() > 0)
355 drawLine(canvas, paint, dashLinePaint, line, offsetX, offsetY);
359 // ここは呼ばれないはず。。。消したはずのものが残っている
360 Log.v(TAG, "DETECTED DELETED LINE");
369 private void drawLine(Canvas canvas, Paint paint, Paint dashPaint, ObjectConnector line, float offsetX, float offsetY)
373 if ((objectHolder == null)||(canvas == null))
379 PositionObject from = objectHolder.getPosition(line.getFromObjectKey());
380 PositionObject to = objectHolder.getPosition(line.getToObjectKey());
381 if ((from == null)||(to == null))
388 paint.setStrokeWidth((float) line.getLineThickness());
391 dashPaint.setStrokeWidth((float) line.getLineThickness());
393 // ラインのスタイル(連続線 or 点線)を設定する
394 Paint linePaint = (line.getLineShape() == LineStyleHolder.LINESHAPE_DASH) ? dashPaint : paint;
396 // 初期値として、各オブジェクトの中心座標を設定する
397 RectF fromRect = from.getRect();
398 RectF toRect = to.getRect();
399 float startX = fromRect.centerX() + offsetX;
400 float endX = toRect.centerX() + offsetX;
401 float startY = fromRect.centerY() + offsetY;
402 float endY = toRect.centerY() + offsetY;
405 if (fromRect.bottom < toRect.top)
407 startY = fromRect.bottom + offsetY;
408 endY = toRect.top + offsetY;
410 else if (fromRect.top > toRect.bottom)
412 startY = fromRect.top + offsetY;
413 endY = toRect.bottom + offsetY;
416 // X座標の線の位置を補正する (Y座標が補正されていないとき)
417 if ((startY != (fromRect.top + offsetY))&&(startY != (fromRect.bottom + offsetY)))
419 if (fromRect.right < toRect.left)
421 startX = fromRect.right + offsetX;
422 endX = toRect.left + offsetX;
424 else if (fromRect.left > toRect.right)
426 startX = fromRect.left + offsetX;
427 endX = toRect.right + offsetX;
431 int lineStyle = line.getLineStyle();
432 if ((lineStyle == LineStyleHolder.LINESTYLE_TREESTYLE_NO_ARROW)||
433 (lineStyle == LineStyleHolder.LINESTYLE_TREESTYLE_L_ARROW)||
434 (lineStyle == LineStyleHolder.LINESTYLE_TREESTYLE_R_ARROW))
437 if (startX == (fromRect.centerX() + offsetX))
439 float middleY = (startY + endY) / 2;
440 canvas.drawLine(startX, startY, startX, middleY, linePaint);
441 canvas.drawLine(startX, middleY, endX, middleY, linePaint);
442 canvas.drawLine(endX, middleY, endX, endY, linePaint);
445 if (lineStyle == LineStyleHolder.LINESTYLE_TREESTYLE_L_ARROW)
448 ObjectShapeDrawer.drawArrowTree(canvas, paint, startX,startY, middleY, false);
450 else if (lineStyle == LineStyleHolder.LINESTYLE_TREESTYLE_R_ARROW)
453 ObjectShapeDrawer.drawArrowTree(canvas, paint, endX, endY, middleY, false);
458 float middleX = (startX + endX) / 2;
459 canvas.drawLine(startX, startY, middleX, startY, linePaint);
460 canvas.drawLine(middleX, startY, middleX, endY, linePaint);
461 canvas.drawLine(middleX, endY, endX, endY, linePaint);
464 if (lineStyle == LineStyleHolder.LINESTYLE_TREESTYLE_L_ARROW)
467 ObjectShapeDrawer.drawArrowTree(canvas, paint, startX, startY, middleX, true);
469 else if (lineStyle == LineStyleHolder.LINESTYLE_TREESTYLE_R_ARROW)
472 ObjectShapeDrawer.drawArrowTree(canvas, paint, endX,endY, middleX, true);
476 else if ((lineStyle == LineStyleHolder.LINESTYLE_CURVESTYLE_NO_ARROW)||
477 (lineStyle == LineStyleHolder.LINESTYLE_CURVESTYLE_L_ARROW)||
478 (lineStyle == LineStyleHolder.LINESTYLE_CURVESTYLE_R_ARROW))
481 float middleX = (startX + endX) / 2;
482 float middleY = (startY + endY) / 2;
483 float x1 = (startX + middleX) / 2;
484 float x2 = (middleX + endX) / 2;
486 Path pathLine = new Path();
487 pathLine.moveTo(startX, startY);
488 pathLine.cubicTo(x1, middleY, x2, middleY, endX, endY);
489 canvas.drawPath(pathLine, linePaint);
492 if (lineStyle == LineStyleHolder.LINESTYLE_CURVESTYLE_L_ARROW)
495 ObjectShapeDrawer.drawArrow(canvas, paint, startX, startY, endX, endY);
497 else if (lineStyle == LineStyleHolder.LINESTYLE_CURVESTYLE_R_ARROW)
500 ObjectShapeDrawer.drawArrow(canvas, paint, endX, endY, startX, startY);
503 else // if (line.lineStyle == MeMoMaConnectLineHolder.LINESTYLE_STRAIGHT)
506 canvas.drawLine(startX, startY, endX, endY, linePaint);
509 if (lineStyle == LineStyleHolder.LINESTYLE_STRAIGHT_L_ARROW)
512 ObjectShapeDrawer.drawArrow(canvas, paint, startX, startY, endX, endY);
514 else if (lineStyle == LineStyleHolder.LINESTYLE_STRAIGHT_R_ARROW)
517 ObjectShapeDrawer.drawArrow(canvas, paint, endX, endY, startX, startY);
524 Log.v(TAG, "EXCEPTION :" + ex.toString());
529 * オブジェクトを動かしている最中かどうかの判定を行う。
532 * @return trueなら、動かしている最中
534 private boolean isFlicking(Canvas canvas)
536 return (!((tempPosX == Float.MIN_VALUE)||(tempPosY == Float.MIN_VALUE)));
544 private void drawTrackAndPositions(Canvas canvas)
547 float x = (tempPosX - drawTransX) / drawScale;
548 float y = (tempPosY - drawTransY) / drawScale;
550 Paint paint = new Paint();
551 paint.setStyle(Paint.Style.STROKE);
552 paint.setColor(Color.GRAY);
553 if (selectedPosition != null)
555 RectF objRect = selectedPosition.getRect();
556 float objX = (objRect.right - objRect.left) / 2;
557 float objY = (objRect.bottom - objRect.top) / 2;
558 canvas.drawLine(objRect.centerX(), objRect.centerY(), x, y, paint);
559 canvas.drawRect((x - objX), (y - objY), (x + objX), (y + objY), paint);
562 drawObject(canvas, selectedPosition, true, 0.0f, 0.0f);
564 else // オブジェクト非選択時の表示
566 int data = selectionReceiver.touchedVacantArea();
567 if (data == OperationModeHolder.OPERATIONMODE_MOVE)
569 // 移動モードのとき... (表示領域を移動させる)
570 drawTransX = (tempPosX - downPosX);
571 drawTransY = (tempPosY - downPosY);
574 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
575 SharedPreferences.Editor editor = preferences.edit();
576 editor.putFloat("drawTransX", drawTransX);
577 editor.putFloat("drawTransY", drawTransY);
583 paint.setColor(Color.YELLOW);
584 canvas.drawLine(((downPosX) / drawScale), ((downPosY) / drawScale), x, y, paint);
593 private void drawObject(Canvas canvas, PositionObject object, boolean isMoving, float offsetX, float offsetY)
595 float label_offsetX = OBJECTLABEL_MARGIN;
596 float label_offsetY = 0.0f;
599 Paint paint = new Paint();
602 paint.setColor(Color.YELLOW);
603 paint.setStyle(Paint.Style.STROKE);
604 paint.setStrokeWidth(object.getstrokeWidth());
608 paint.setColor(object.getObjectColor());
609 paint.setStyle(Paint.Style.valueOf(object.getPaintStyle()));
610 paint.setStrokeWidth(object.getstrokeWidth());
614 RectF objectShape = new RectF(object.getRect());
615 objectShape.left = objectShape.left + offsetX;
616 objectShape.right = objectShape.right + offsetX;
617 objectShape.top = objectShape.top + offsetY;
618 objectShape.bottom = objectShape.bottom + offsetY;
620 int drawStyle = object.getDrawStyle();
621 if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_OVAL)
624 label_offsetY = ObjectShapeDrawer.drawObjectOval(canvas, objectShape, paint);
626 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_ROUNDRECT)
629 label_offsetY = ObjectShapeDrawer.drawObjectRoundRect(canvas, objectShape, paint);
631 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_DIAMOND)
634 label_offsetY = ObjectShapeDrawer.drawObjectDiamond(canvas, objectShape, paint);
635 label_offsetX = OBJECTLABEL_MARGIN;
637 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_KEYBOARD)
640 label_offsetY = ObjectShapeDrawer.drawObjectKeyboard(canvas, objectShape, paint);
642 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_PARALLELOGRAM)
645 label_offsetY = ObjectShapeDrawer.drawObjectParallelogram(canvas, objectShape, paint);
647 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_HEXAGONAL)
650 label_offsetY = ObjectShapeDrawer.drawObjectHexagonal(canvas, objectShape, paint);
652 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_PAPER)
655 label_offsetY = ObjectShapeDrawer.drawObjectPaper(canvas, objectShape, paint);
657 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_DRUM)
660 label_offsetY = ObjectShapeDrawer.drawObjectDrum(canvas, objectShape, paint, Paint.Style.valueOf(object.getPaintStyle()));
662 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_CIRCLE)
665 label_offsetY = ObjectShapeDrawer.drawObjectCircle(canvas, objectShape, paint);
667 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_NO_REGION)
669 // 枠なしを描画(?)する ... なにもしない
670 if (object.getLabel().length() == 0)
672 // 何も表示しないとわからないので、ラベルが無いときには枠を表示する
673 ObjectShapeDrawer.drawObjectNoRegion(canvas, objectShape, paint);
676 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_LOOP_START)
679 label_offsetY = ObjectShapeDrawer.drawObjectLoopStart(canvas, objectShape, paint);
681 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_LOOP_END)
684 label_offsetY = ObjectShapeDrawer.drawObjectLoopEnd(canvas, objectShape, paint);
686 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_LEFT_ARROW)
689 label_offsetY = ObjectShapeDrawer.drawObjectLeftArrow(canvas, objectShape, paint);
691 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_DOWN_ARROW)
694 label_offsetY = ObjectShapeDrawer.drawObjectDownArrow(canvas, objectShape, paint);
696 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_UP_ARROW)
699 label_offsetY = ObjectShapeDrawer.drawObjectUpArrow(canvas, objectShape, paint);
701 else if (drawStyle == MeMoMaObjectHolder.DRAWSTYLE_RIGHT_ARROW)
704 label_offsetY = ObjectShapeDrawer.drawObjectRightArrow(canvas, objectShape, paint);
706 else // if (pos.drawStyle == MeMoMaObjectHolder.DRAWSTYLE_RECTANGLE)
709 label_offsetY = ObjectShapeDrawer.drawObjectRect(canvas, objectShape, paint);
713 paint.setTextSize(object.getFontSize());
716 ObjectShapeDrawer.drawTextLabel(canvas, paint, object, objectShape, displayObjectInformation, label_offsetX, label_offsetY);
724 private void drawObjects(Canvas canvas , float offsetX, float offsetY)
726 // オブジェクトの描画 (保持しているものはすべて表示する)
727 Enumeration<Integer> keys = objectHolder.getObjectKeys();
728 while (keys.hasMoreElements())
730 Integer key = keys.nextElement();
731 PositionObject pos = objectHolder.getPosition(key);
732 drawObject(canvas, pos, false, offsetX, offsetY);
740 private boolean onTouchDown(MotionEvent event)
743 downPosX = event.getX() - drawTransX;
744 downPosY = event.getY() - drawTransY;
746 // タッチ位置をオブジェクト画像の座標に変換する
747 float x = downPosX / drawScale;
748 float y = downPosY / drawScale;
750 // タッチ位置にオブジェクトが存在するか確認する
751 selectedPosition = checkSelectedObject(x, y);
752 if (selectedPosition == null)
754 // 最初にタップしたときの位置を selectedPositionに設定する
755 int data = selectionReceiver.touchedVacantArea();
756 if (data == OperationModeHolder.OPERATIONMODE_CREATE)
758 // オブジェクト作成モードのとき...オブジェクトを生成する
759 selectedPosition = objectHolder.createPosition(x, y, objectStyle);
761 // オブジェクトが生成されたことを通知する
762 selectionReceiver.objectCreated();
765 else if (data ==OperationModeHolder.OPERATIONMODE_MOVE)
769 else // if (data ==ChangeDrawMode.OPERATIONMODE_DELETE)
782 private boolean onTouchUp(MotionEvent event)
784 boolean longPress = false;
785 if (onGestureProcessed)
787 // ロングタッチ中だった場合...フラグを落とす
788 onGestureProcessed = false;
792 // タッチ位置をオブジェクト画像の座標に変換する
793 float x = (event.getX() - drawTransX) / drawScale;
794 float y = (event.getY() - drawTransY) / drawScale;
796 if (selectedPosition == null)
798 int data = selectionReceiver.touchUppedVacantArea();
799 if (data == OperationModeHolder.OPERATIONMODE_DELETE)
801 if ((tempPosX == Float.MIN_VALUE)||(tempPosY == Float.MIN_VALUE)||(downPosX == Float.MIN_VALUE)||(downPosY == Float.MIN_VALUE))
803 // タッチが2つ揃っていないので、何もしない。
804 Log.v(TAG, "onTouchUp : (" + downPosX + "," + downPosY + ") [" + drawScale + "] (" + tempPosX + "," + tempPosY + ") [" + drawTransX + "," + drawTransY + "]");
808 // タッチが離された位置にオブジェクトがおらず、オブジェクトが非選択だった場合...オブジェクトが繋がっているラインを切断する
809 disconnectObjects((downPosX / drawScale) , (downPosY / drawScale), ((tempPosX - drawTransX) / drawScale), ((tempPosY - drawTransY) / drawScale));
812 tempPosX = Float.MIN_VALUE;
813 tempPosY = Float.MIN_VALUE;
814 downPosX = Float.MIN_VALUE;
815 downPosY = Float.MIN_VALUE;
820 tempPosX = Float.MIN_VALUE;
821 tempPosY = Float.MIN_VALUE;
822 downPosX = Float.MIN_VALUE;
823 downPosY = Float.MIN_VALUE;
827 RectF selectedRect = selectedPosition.getRect();
828 if (selectedRect.contains(x, y))
830 // タッチが離された位置がタッチしたオブジェクトと同じ位置だった場合......
833 float diffX = Math.abs(event.getX() - drawTransX - downPosX);
834 float diffY = Math.abs(event.getY() - drawTransY - downPosY);
836 // タッチが離された位置が動いていた場合、オブジェクト位置の微調整と判定する。
837 if (((diffX > 2.0f)||(diffY > 2.0f))||(longPress))
839 // タッチが離された場所にはオブジェクトがなかった場合...オブジェクトをその位置に移動させる
840 Log.v(TAG, "MOVE OBJECT : (" + diffX + "," + diffY + ")");
841 moveObjectPosition(x, y);
845 // タッチが押された位置と離された位置が同じ位置だった場合......アイテムが選択された、と認識する。
846 Log.v(TAG, " ITEM SELECTED :" + x + "," + y);
847 if (selectionReceiver != null)
850 boolean isDraw = selectionReceiver.objectSelected(selectedPosition.getKey());
853 tempPosX = Float.MIN_VALUE;
854 tempPosY = Float.MIN_VALUE;
859 // タッチが離された位置にオブジェクトがいるかどうかのチェック
860 PositionObject position = checkSelectedObject(x, y);
861 if ((position != null)&&(!longPress))
863 // 他のオブジェクトと重なるように操作した、この場合は、オブジェクト間を線をつなげる
864 // (ただし、ボタンを長押ししていなかったとき。)
865 lineHolder.setLines(selectedPosition.getKey(), position.getKey(), lineStyleHolder);
866 tempPosX = Float.MIN_VALUE;
867 tempPosY = Float.MIN_VALUE;
871 // タッチが離された場所にはオブジェクトがなかった場合...オブジェクトをその位置に移動させる
872 moveObjectPosition(x, y);
874 tempPosX = Float.MIN_VALUE;
875 tempPosY = Float.MIN_VALUE;
876 float positionX = alignPosition(x, (objectSizeX / 2) * (-1));
877 float positionY = alignPosition(y, (objectSizeY / 2) * (-1));
878 selectedPosition.rect = new android.graphics.RectF(positionX, positionY, (positionX + objectSizeX), (positionY + objectSizeY));
879 // selectedPosition.drawStyle = objectStyle; // 不要、最初に生成するときだけ必要
888 private void moveObjectPosition(float x, float y)
890 RectF curRect = selectedPosition.getRect();
891 tempPosX = Float.MIN_VALUE;
892 tempPosY = Float.MIN_VALUE;
893 float sizeX = curRect.right - curRect.left;
894 float sizeY = curRect.bottom - curRect.top;
896 float positionX = alignPosition(x, (sizeX / 2) * (-1));
897 float positionY = alignPosition(y, (sizeY / 2) * (-1));
898 selectedPosition.setRect(new android.graphics.RectF(positionX, positionY, (positionX + sizeX), (positionY + sizeY)));
902 * onTouchEvent : 画面がタッチした時のイベント処理
903 * (true なら、画面描画を実施する)
905 public boolean onTouchEvent(MotionEvent event)
909 // スケールジェスチャ(マルチタッチのジェスチャ)を拾う
910 // isDraw = scaleGestureDetector.onTouchEvent(event);
911 if ((onScaling)||(scaleGestureDetector.isInProgress()))
917 // 先にジェスチャーを拾ってみよう...
918 isDraw = gestureDetector.onTouchEvent(event);
921 Log.v(TAG, "MeMoMaCanvasDrawer::onTouchEvent() : isDraw == true");
925 int action = event.getAction();
927 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::onTouchEvent() : " + action);
928 if (action == MotionEvent.ACTION_DOWN)
931 isDraw = onTouchDown(event);
933 else if (action == MotionEvent.ACTION_MOVE)
935 // タッチされたまま動かされたときの処理
936 tempPosX = event.getX();
937 tempPosY = event.getY();
940 else if (action == MotionEvent.ACTION_UP)
943 isDraw = onTouchUp(event);
950 * タテヨコ位置を合わせられるよう、調整する。
953 private float alignPosition(float pos, float offset)
956 return (pos + offset);
960 * 位置から判定し、選択したオブジェクトを応答する
961 * (オブジェクトが選択されていない場合には、nullを応答する)
964 private PositionObject checkSelectedObject(float x, float y)
966 Enumeration<Integer> keys = objectHolder.getObjectKeys();
967 //Log.v(Main.APP_IDENTIFIER, "CHECK POS " + x + "," + y);
968 while (keys.hasMoreElements())
970 Integer key = keys.nextElement();
971 PositionObject pos = objectHolder.getPosition(key);
972 RectF posRect = pos.getRect();
973 if (posRect.contains(x, y))
975 Log.v(TAG, "SELECTED :" + posRect.centerX() + "," + posRect.centerY() + " KEY :" + key);
978 //Log.v(Main.APP_IDENTIFIER, "NOT MATCH :" + pos.rect.centerX() + "," + pos.rect.centerY());
980 //Log.v(Main.APP_IDENTIFIER, "RETURN NULL...");
985 * 線と交差するオブジェクト接続線をすべて削除する
988 private void disconnectObjects(float startX, float startY, float endX, float endY)
990 Log.v(TAG, "MeMoMaCanvasDrawer::disconnectObjects() [" + startX + "," + startY +"]-[" + endX + "," + endY + "]");
993 Enumeration<Integer> keys = lineHolder.getLineKeys();
994 while (keys.hasMoreElements())
996 Integer key = keys.nextElement();
997 ObjectConnector line = lineHolder.getLine(key);
998 if (line.getKey() > 0)
1001 RectF fromRect = objectHolder.getPosition(line.getFromObjectKey()).getRect();
1002 RectF toRect = objectHolder.getPosition(line.getToObjectKey()).getRect();
1005 if (checkIntersection(startX, startY, endX, endY, fromRect.centerX(), fromRect.centerY(), toRect.centerX(), toRect.centerY()))
1008 //Log.v(Main.APP_IDENTIFIER, "CUT LINE [" + from.rect.centerX() + "," + from.rect.centerY() +"]-[" + to.rect.centerX() + "," + to.rect.centerY() + "]");
1009 lineHolder.disconnectLines(line.getKey());
1014 catch (Exception ex)
1023 * @param x1 線1の始点 (X座標)
1024 * @param y1 線1の始点 (Y座標)
1025 * @param x2 線1の終点 (X座標)
1026 * @param y2 線1の終点 (Y座標)
1027 * @param x3 線2の始点 (X座標)
1028 * @param y3 線2の始点 (Y座標)
1029 * @param x4 線2の終点 (X座標)
1030 * @param y4 線2の終点 (Y座標)
1031 * @return true なら線が交差している
1033 private boolean checkIntersection(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
1036 float denominator = (x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3);
1037 if (Math.abs(denominator) < 0.00001)
1043 float tempX = x3 - x1;
1044 float tempY = y3 - y1;
1045 float dR = (((y4 - y3) * tempX) - ((x4 - x3) * tempY)) / denominator;
1046 float dS = (((y2 - y1) * tempX) - ((x2 - x1) * tempY)) / denominator;
1049 //float crossX, crossY;
1050 //crossX = x1 + dR * (x2 - x1);
1051 //crossY = y1 + dR * (y2 - y1);
1053 // 交点が線分内にあるかどうかをチェックする
1054 return ((dR >= 0)&&(dR <= 1)&&(dS >= 0)&&(dS <= 1));
1058 * 並行移動・ズームのサイズをリセットする
1061 public void resetScaleAndLocation(SeekBar zoomBar)
1067 // プログレスバーの位置をリセットする
1069 zoomBar.setProgress(50);
1071 // preferenceに状態を記録する
1072 recordTranslateAndZoomScale(50);
1078 private void zoomScaleChanged(int progress)
1080 float val = ((float) progress - 50.0f) / 50.0f;
1083 float prevSizeWidth = screenWidth * drawScale;
1084 float prevSizeHeight = screenHeight * drawScale;
1086 // 表示倍率を変更し、倍率を画面に表示する
1087 drawScale = (float) Math.round(Math.pow(10.0, val) * 10.0) / 10.0f;
1088 TextView textview = parent.findViewById(R.id.ZoomRate);
1089 String showText = "x" + drawScale;
1090 textview.setText(showText);
1093 float showSizeWidth = screenWidth * drawScale;
1094 float showSizeHeight = screenHeight * drawScale;
1096 // 倍率にあわせて並行移動する場所を調整する
1097 drawTransX = (prevSizeWidth - showSizeWidth) / 2.0f + drawTransX;
1098 drawTransY = (prevSizeHeight - showSizeHeight) / 2.0f + drawTransY;
1100 // preferenceに状態を記録する
1101 recordTranslateAndZoomScale(progress);
1108 private void recordTranslateAndZoomScale(int progress)
1110 //Log.v(Main.APP_IDENTIFIER, "recordTranslateAndZoomScale() : x" + drawScale + " X:" + drawTransX + " Y: " + drawTransY);
1111 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
1112 SharedPreferences.Editor editor = preferences.edit();
1113 editor.putFloat("drawScale", drawScale);
1114 editor.putFloat("drawTransX", drawTransX);
1115 editor.putFloat("drawTransY", drawTransY);
1116 editor.putInt("zoomProgress", progress);
1124 private void restoreTranslateAndZoomScale()
1126 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
1127 drawScale = preferences.getFloat("drawScale", 1.0f);
1128 drawTransX = preferences.getFloat("drawTransX", 0.0f);
1129 drawTransY = preferences.getFloat("drawTransY", 0.0f);
1130 Log.v(TAG, "restoreTranslateAndZoomScale() : x" + drawScale + " X:" + drawTransX + " Y: " + drawTransY);
1134 * GestureDetector.OnGestureListener の実装
1136 public boolean onDown(MotionEvent event)
1138 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::onDown() " + event.getX() + "," + event.getY());
1143 * GestureDetector.OnGestureListener の実装
1145 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
1147 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::onFling() " + velocityX + "," + velocityY);
1152 * GestureDetector.OnGestureListener の実装
1154 public void onLongPress(MotionEvent event)
1156 Log.v(TAG, "MeMoMaCanvasDrawer::onLongPress() " + event.getX() + "," + event.getY());
1158 // タッチ位置をオブジェクト画像の座標に変換する
1159 float x = (event.getX() - drawTransX) / drawScale;
1160 float y = (event.getY() - drawTransY) / drawScale;
1162 // タッチ位置にオブジェクトが存在するか確認する
1163 PositionObject position = checkSelectedObject(x, y);
1164 if (position != null)
1166 // 長押し処理を実施していることを記憶する
1167 onGestureProcessed = true;
1169 // タッチした場所にオブジェクトが存在した!!
1170 selectionReceiver.objectSelectedContext(position.getKey());
1175 * GestureDetector.OnGestureListener の実装
1177 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
1179 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::onScroll() " + distanceX + "," + distanceY);
1184 * GestureDetector.OnGestureListener の実装
1186 public void onShowPress(MotionEvent event)
1188 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::onShowPress() " + event.getX() + "," + event.getY());
1192 * GestureDetector.OnGestureListener の実装
1194 public boolean onSingleTapUp(MotionEvent event)
1196 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::onSingleTapUp() " + event.getX() + "," + event.getY());
1202 * (SeekBar.OnSeekBarChangeListener の実装)
1204 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
1207 zoomScaleChanged(progress);
1210 final GokigenSurfaceView surfaceView = parent.findViewById(R.id.GraphicView);
1211 surfaceView.doDraw();
1215 * SeekBar.OnSeekBarChangeListener の実装
1217 public void onStartTrackingTouch(SeekBar seekBar)
1223 * SeekBar.OnSeekBarChangeListener の実装
1225 public void onStopTrackingTouch(SeekBar seekBar)
1231 * (ScaleGestureDetector.OnScaleGestureListener の実装)
1235 public boolean onScale(ScaleGestureDetector detector)
1237 float scaleFactor = detector.getScaleFactor();
1238 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::onScale() : " + scaleFactor + " (" + currentScaleBar + ")");
1240 // 画面表示の倍率が変更された! x < 1 : 縮小、 1 < x : 拡大
1241 if (scaleFactor < 1.0f)
1243 currentScaleBar = (currentScaleBar == 0) ? 0 : currentScaleBar - 1;
1245 else if (scaleFactor > 1.0f)
1247 currentScaleBar = (currentScaleBar == 100) ? 100 : currentScaleBar + 1;
1249 zoomScaleChanged(currentScaleBar);
1255 * (ScaleGestureDetector.OnScaleGestureListener の実装)
1259 public boolean onScaleBegin(ScaleGestureDetector detector)
1261 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::onScaleBegin() ");
1262 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
1263 currentScaleBar = preferences.getInt("zoomProgress", 50);
1269 * (ScaleGestureDetector.OnScaleGestureListener の実装)
1272 public void onScaleEnd(ScaleGestureDetector detector)
1274 //Log.v(Main.APP_IDENTIFIER, "MeMoMaCanvasDrawer::onScaleEnd() " + currentScaleBar);
1278 final SeekBar seekbar = parent.findViewById(R.id.ZoomInOut);
1279 seekbar.setProgress(currentScaleBar);
1280 zoomScaleChanged(currentScaleBar);