/* @file ProjectionDialog.java * * @author marco corvi * @date nov 2011 * * @brief TopoDroid main drawing activity * -------------------------------------------------------- * Copyright This sowftare is distributed under GPL-3.0 or later * See the file COPYING. * -------------------------------------------------------- */ package com.topodroid.DistoX; import android.app.Dialog; import android.content.Context; // import android.content.res.Resources; // import android.content.pm.PackageManager; import android.graphics.Paint; import android.graphics.Paint.FontMetrics; import android.graphics.PointF; import android.graphics.Path; import android.os.Bundle; import android.os.Handler; import android.os.Message; // import android.view.Menu; // import android.view.SubMenu; // import android.view.MenuItem; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.view.ViewGroup; import android.view.Display; import android.util.DisplayMetrics; // import android.view.ContextMenu; // import android.view.ContextMenu.ContextMenuInfo; import android.widget.Button; import android.widget.ZoomControls; import android.widget.ZoomButton; import android.widget.ZoomButtonsController; import android.widget.ZoomButtonsController.OnZoomListener; import android.widget.Toast; import android.widget.EditText; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import java.util.List; // import java.util.ArrayList; import java.util.concurrent.RejectedExecutionException; // import java.util.Deque; // only API-9 import android.util.Log; /** */ public class ProjectionDialog extends MyDialog implements View.OnTouchListener , View.OnClickListener , OnZoomListener , IZoomer { private View mZoomView; private TopoDroidApp mApp; private ShotWindow mParent; private ProjectionSurface mDrawingSurface; private SeekBar mSeekBar; private Button mBtnOk; private EditText mETazimuth; private DistoXNum mNum; ZoomButtonsController mZoomBtnsCtrl = null; boolean mZoomBtnsCtrlOn = false; private float oldDist; // zoom pointer-spacing private int mTouchMode = DrawingWindow.MODE_MOVE; private float mSaveX; private float mSaveY; private float mSave0X; private float mSave0Y; private float mSave1X; private float mSave1Y; private PointF mOffset = new PointF( 0f, 0f ); private PointF mDisplayCenter; private float mZoom = 1.0f; private long mSid; // survey id private String mName; private String mFrom; private int mAzimuth = 0; private float mBorderRight = 4096; private float mBorderLeft = 0; private float mBorderInnerRight = 4096; private float mBorderInnerLeft = 0; private float mBorderBottom = 4096; List<DistoXDBlock> mList = null; public ProjectionDialog( Context context, ShotWindow parent, long sid, String name, String from ) { super( context, R.string.ProjectionDialog ); // FIXME mParent = parent; mSid = sid; mName = name; mFrom = from; mAzimuth = 0; mApp = mParent.getApp(); } // ------------------------------------------------------------------- // ZOOM CONTROLS public float zoom() { return mZoom; } @Override public void onVisibilityChanged(boolean visible) { if ( mZoomBtnsCtrlOn && mZoomBtnsCtrl != null ) { mZoomBtnsCtrl.setVisible( visible || ( TDSetting.mZoomCtrl > 1 ) ); } } @Override public void onZoom( boolean zoomin ) { if ( zoomin ) changeZoom( DrawingWindow.ZOOM_INC ); else changeZoom( DrawingWindow.ZOOM_DEC ); } private void changeZoom( float f ) { float zoom = mZoom; mZoom *= f; // Log.v( TopoDroidApp.TAG, "zoom " + mZoom ); mOffset.x -= mDisplayCenter.x*(1/zoom-1/mZoom); mOffset.y -= mDisplayCenter.y*(1/zoom-1/mZoom); // Log.v("DistoX", "change zoom " + mOffset.x + " " + mOffset.y + " " + mZoom ); mDrawingSurface.setTransform( mOffset.x, mOffset.y, mZoom ); // mDrawingSurface.refresh(); // mZoomCtrl.hide(); // if ( mZoomBtnsCtrlOn ) mZoomBtnsCtrl.setVisible( false ); } public void zoomIn() { changeZoom( DrawingWindow.ZOOM_INC ); } public void zoomOut() { changeZoom( DrawingWindow.ZOOM_DEC ); } // public void zoomOne() { resetZoom( ); } // public void zoomView( ) // { // // TDLog.Log( TDLog.LOG_PLOT, "zoomView "); // DrawingZoomDialog zoom = new DrawingZoomDialog( mDrawingSurface.getContext(), this ); // zoom.show(); // } // ----------------------------------------------------------------- private void addFixedLine( DistoXDBlock blk, float x1, float y1, float x2, float y2, boolean splay ) { DrawingPath dpath = null; if ( splay ) { dpath = new DrawingPath( DrawingPath.DRAWING_PATH_SPLAY, blk ); dpath.setPaint( BrushManager.fixedShotPaint ); } else { dpath = new DrawingPath( DrawingPath.DRAWING_PATH_FIXED, blk ); dpath.setPaint( BrushManager.labelPaint ); } // DrawingUtil.makePath( dpath, x1, y1, x2, y2, mOffset.x, mOffset.y ); dpath.mPath = new Path(); dpath.mPath.moveTo( x1, y1 ); dpath.mPath.lineTo( x2, y2 ); mDrawingSurface.addFixedPath( dpath, splay ); } // -------------------------------------------------------------------------------------- private void computeReferences( ) { mDrawingSurface.clearReferences( ); // Log.v("DistoX", "refs " + mOffset.x + " " + mOffset.y + " " + mZoom + " " + mAzimuth ); float cosp = TDMath.cosd( mAzimuth ); float sinp = TDMath.sind( mAzimuth ); List< NumStation > stations = mNum.getStations(); List< NumShot > shots = mNum.getShots(); List< NumSplay > splays = mNum.getSplays(); float h1, h2, v1, v2; // float dx = 0; // mOffset.x; // float dy = 0; // mOffset.y; for ( NumShot sh : shots ) { NumStation st1 = sh.from; NumStation st2 = sh.to; if ( st1.show() && st2.show() ) { h1 = DrawingUtil.toSceneX( (float)( st1.e * cosp + st1.s * sinp ) ); // - dx; h2 = DrawingUtil.toSceneX( (float)( st2.e * cosp + st2.s * sinp ) ); // - dx; v1 = DrawingUtil.toSceneY( (float)( st1.v ) ); // - dy; v2 = DrawingUtil.toSceneY( (float)( st2.v ) ); // - dy; addFixedLine( sh.getFirstBlock(), h1, v1, h2, v2, false ); } } for ( NumSplay sp : splays ) { NumStation st = sp.from; if ( st.show() ) { h1 = DrawingUtil.toSceneX( (float)( st.e * cosp + st.s * sinp ) ); // - dx; h2 = DrawingUtil.toSceneX( (float)( sp.e * cosp + sp.s * sinp ) ); // - dx; v1 = DrawingUtil.toSceneY( (float)( st.v ) ); // - dy; v2 = DrawingUtil.toSceneY( (float)( sp.v ) ); // - dy; addFixedLine( sp.getBlock(), h1, v1, h2, v2, true ); } } for ( NumStation st : stations ) { if ( st.show() ) { h1 = DrawingUtil.toSceneX( (float)( st.e * cosp + st.s * sinp ) ); // - dx; v1 = DrawingUtil.toSceneY( (float)( st.v ) ); // - dy; mDrawingSurface.addDrawingStationName( st, h1, v1 ); } } setTitle( String.format( mContext.getResources().getString(R.string.title_projection), mAzimuth ) ); } // -------------------------------------------------------------- // this method is a callback to let other objects tell the activity to use zooms or not private void switchZoomCtrl( int ctrl ) { // Log.v("DistoX", "DEBUG switchZoomCtrl " + ctrl + " ctrl is " + ((mZoomBtnsCtrl == null )? "null" : "not null") ); if ( mZoomBtnsCtrl == null ) return; mZoomBtnsCtrlOn = (ctrl > 0); switch ( ctrl ) { case 0: mZoomBtnsCtrl.setOnZoomListener( null ); mZoomBtnsCtrl.setVisible( false ); mZoomBtnsCtrl.setZoomInEnabled( false ); mZoomBtnsCtrl.setZoomOutEnabled( false ); mZoomView.setVisibility( View.GONE ); break; case 1: mZoomView.setVisibility( View.VISIBLE ); mZoomBtnsCtrl.setOnZoomListener( this ); mZoomBtnsCtrl.setVisible( false ); mZoomBtnsCtrl.setZoomInEnabled( true ); mZoomBtnsCtrl.setZoomOutEnabled( true ); break; case 2: mZoomView.setVisibility( View.VISIBLE ); mZoomBtnsCtrl.setOnZoomListener( this ); mZoomBtnsCtrl.setVisible( true ); mZoomBtnsCtrl.setZoomInEnabled( true ); mZoomBtnsCtrl.setZoomOutEnabled( true ); break; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mZoomBtnsCtrlOn = (TDSetting.mZoomCtrl > 1); // do before setting content // Display display = getWindowManager().getDefaultDisplay(); // DisplayMetrics dm = new DisplayMetrics(); // display.getMetrics( dm ); // int width = dm widthPixels; int width = mContext.getResources().getDisplayMetrics().widthPixels; // mIsNotMultitouch = ! getPackageManager().hasSystemFeature( PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH ); setContentView( R.layout.projection_dialog ); mSeekBar = (SeekBar) findViewById(R.id.seekbar ); mETazimuth = (EditText) findViewById( R.id.textform ); mBtnOk = (Button) findViewById( R.id.btn_ok ); mBtnOk.setOnClickListener( this ); mZoom = mApp.mScaleFactor; // canvas zoom mBorderRight = mApp.mDisplayWidth * 15 / 16; mBorderLeft = mApp.mDisplayWidth / 16; mBorderInnerRight = mApp.mDisplayWidth * 3 / 4; mBorderInnerLeft = mApp.mDisplayWidth / 4; mBorderBottom = mApp.mDisplayHeight * 7 / 8; mDisplayCenter = new PointF(mApp.mDisplayWidth / 2, mApp.mDisplayHeight / 2); // Log.v("DistoX", "surface " + mOffset.x + " " + mOffset.y + " " + mZoom ); mDrawingSurface = (ProjectionSurface) findViewById(R.id.drawingSurface); // mDrawingSurface.setZoomer( this ); mDrawingSurface.setProjectionDialog( this ); mDrawingSurface.setOnTouchListener(this); // mDrawingSurface.setOnLongClickListener(this); // mDrawingSurface.setBuiltInZoomControls(true); mZoomView = (View) findViewById(R.id.zoomView ); mZoomBtnsCtrl = new ZoomButtonsController( mZoomView ); // FIXME ZOOM_CTRL mZoomCtrl = (ZoomControls) mZoomBtnsCtrl.getZoomControls(); // ViewGroup vg = mZoomBtnsCtrl.getContainer(); // switchZoomCtrl( TDSetting.mZoomCtrl ); // mETazimuth.setText( Integer.toString( mAzimuth ) ); mSeekBar.setOnSeekBarChangeListener( new OnSeekBarChangeListener() { public void onProgressChanged( SeekBar seekbar, int progress, boolean fromUser) { mAzimuth = (int)( (160 + progress)%360 ); if ( progress < 10 ) { seekbar.setProgress( progress + 360 ); } else if ( progress > 390 ) { seekbar.setProgress( progress - 360 ); } else { computeReferences(); mETazimuth.setText( Integer.toString( mAzimuth ) ); } // Log.v("DistoX", "set azimuth " + mAzimuth ); } public void onStartTrackingTouch(SeekBar seekbar) { } public void onStopTrackingTouch(SeekBar seekbar) { } } ); mETazimuth.setOnFocusChangeListener( new View.OnFocusChangeListener() { public void onFocusChange( View v, boolean b ) { if ( ! b ) { // focus lost try { setAzimuth( Integer.parseInt( mETazimuth.getText().toString() ) ); } catch ( NumberFormatException e ) { } } } } ); mETazimuth.setOnKeyListener( new View.OnKeyListener() { public boolean onKey( View v, int code, KeyEvent event ) { // Log.v("DistoX", "key code " + code ); if ( code == 66 /* KeyEvent.KEYCODE_ENTER */ ) { try { setAzimuth( Integer.parseInt( mETazimuth.getText().toString() ) ); } catch ( NumberFormatException e ) { } return true; } return false; } } ); doStart(); } void setAzimuth( int a ) { mAzimuth = a; if ( mAzimuth < 0 || mAzimuth >= 360 ) mAzimuth = 0; computeReferences(); mSeekBar.setProgress( ( mAzimuth < 180 )? 200 + mAzimuth : mAzimuth - 160 ); } void setSize( int w, int h ) { mOffset.x = w/2; mOffset.y = h/2; mDrawingSurface.setTransform( mOffset.x, mOffset.y, mZoom ); } // ---------------------------------------------------------------------------- private void doStart() { mList = mApp.mData.selectAllShots( mSid, TopoDroidApp.STATUS_NORMAL ); if ( mList.size() == 0 ) { dismiss(); Toast.makeText( mContext, R.string.few_data, Toast.LENGTH_SHORT ).show(); } else { // float decl = mApp.mData.getSurveyDeclination( mSid ); mNum = new DistoXNum( mList, mFrom, "", "", 0.0f ); mSeekBar.setProgress( 200 ); float de = - mNum.surveyEmin(); if ( mNum.surveyEmax() > de ) de = mNum.surveyEmax(); float ds = - mNum.surveySmin(); if ( mNum.surveySmax() > ds ) ds = mNum.surveySmax(); mZoom *= 2 / (float)Math.sqrt( de*de + ds*ds ); // mOffset.x = 2 * mDisplayCenter.x; // + (mNum.surveyEmax() + mNum.surveyEmin()) * DrawingUtil.SCALE_FIX/2; // mOffset.y = 2 * mDisplayCenter.y; // - (mNum.surveySmax() + mNum.surveySmin()) * DrawingUtil.SCALE_FIX/2; // Log.v("DistoX", "start " + de + " " + ds + " " + dr + " off " + mOffset.x + " " + mOffset.y + " " + mZoom ); computeReferences(); mDrawingSurface.setTransform( mOffset.x, mOffset.y, mZoom ); } } float spacing( MotionEventWrap ev ) { int np = ev.getPointerCount(); if ( np < 2 ) return 0.0f; float x = ev.getX(1) - ev.getX(0); float y = ev.getY(1) - ev.getY(0); return (float)Math.sqrt(x*x + y*y); } void saveEventPoint( MotionEventWrap ev ) { int np = ev.getPointerCount(); if ( np >= 1 ) { mSave0X = ev.getX(0); mSave0Y = ev.getY(0); if ( np >= 2 ) { mSave1X = ev.getX(1); mSave1Y = ev.getY(1); } else { mSave1X = mSave0X; mSave1Y = mSave0Y; } } } void shiftByEvent( MotionEventWrap ev ) { float x0 = 0.0f; float y0 = 0.0f; float x1 = 0.0f; float y1 = 0.0f; int np = ev.getPointerCount(); if ( np >= 1 ) { x0 = ev.getX(0); y0 = ev.getY(0); if ( np >= 2 ) { x1 = ev.getX(1); y1 = ev.getY(1); } else { x1 = x0; y1 = y0; } } float x_shift = ( x0 - mSave0X + x1 - mSave1X ) / 2; float y_shift = ( y0 - mSave0Y + y1 - mSave1Y ) / 2; mSave0X = x0; mSave0Y = y0; mSave1X = x1; mSave1Y = y1; moveCanvas( x_shift, y_shift ); } private void moveCanvas( float x_shift, float y_shift ) { if ( Math.abs( x_shift ) < 60 && Math.abs( y_shift ) < 60 ) { mOffset.x += x_shift / mZoom; // add shift to offset mOffset.y += y_shift / mZoom; // Log.v("DistoX", "move canvas " + mOffset.x + " " + mOffset.y + " " + mZoom ); mDrawingSurface.setTransform( mOffset.x, mOffset.y, mZoom ); // mDrawingSurface.refresh(); } } public void checkZoomBtnsCtrl() { // if ( mZoomBtnsCtrl == null ) return; // not necessary if ( TDSetting.mZoomCtrl == 2 && ! mZoomBtnsCtrl.isVisible() ) { mZoomBtnsCtrl.setVisible( true ); } } private boolean pointerDown = false; public boolean onTouch( View view, MotionEvent rawEvent ) { checkZoomBtnsCtrl(); MotionEventWrap event = MotionEventWrap.wrap(rawEvent); // TDLog.Log( TDLog.LOG_INPUT, "DrawingWindow onTouch() " ); // dumpEvent( event ); int act = event.getAction(); int action = act & MotionEvent.ACTION_MASK; int id = 0; if (action == MotionEvent.ACTION_POINTER_DOWN) { mTouchMode = DrawingWindow.MODE_ZOOM; oldDist = spacing( event ); saveEventPoint( event ); pointerDown = true; return true; } else if ( action == MotionEvent.ACTION_POINTER_UP) { int np = event.getPointerCount(); if ( np > 2 ) return true; mTouchMode = DrawingWindow.MODE_MOVE; id = 1 - ((act & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT); // int idx = rawEvent.findPointerIndex( id ); /* fall through */ } float x_canvas = event.getX(id); float y_canvas = event.getY(id); // Log.v("DistoX", "touch " + x_canvas + " " + y_canvas + " (" + mOffset.x + " " + mOffset.y + " " + mZoom + ")" ); // ---------------------------------------- DOWN if (action == MotionEvent.ACTION_DOWN) { // TDLog.Log( TDLog.LOG_PLOT, "DOWN at X " + x_canvas + " [" +mBorderInnerLeft + " " + mBorderInnerRight + "] Y " // + y_canvas + " / " + mBorderBottom ); if ( y_canvas > mBorderBottom ) { if ( mZoomBtnsCtrlOn && x_canvas > mBorderInnerLeft && x_canvas < mBorderInnerRight ) { mTouchMode = DrawingWindow.MODE_ZOOM; mZoomBtnsCtrl.setVisible( true ); // mZoomCtrl.show( ); } else if ( TDSetting.mSideDrag ) { mTouchMode = DrawingWindow.MODE_ZOOM; } } else if ( TDSetting.mSideDrag && ( x_canvas > mBorderRight || x_canvas < mBorderLeft ) ) { mTouchMode = DrawingWindow.MODE_ZOOM; } // setTheTitle( ); mSaveX = x_canvas; // FIXME-000 mSaveY = y_canvas; return false; // ---------------------------------------- MOVE } else if ( action == MotionEvent.ACTION_MOVE ) { if ( mTouchMode == DrawingWindow.MODE_MOVE) { float x_shift = x_canvas - mSaveX; // compute shift float y_shift = y_canvas - mSaveY; moveCanvas( x_shift, y_shift ); mSaveX = x_canvas; mSaveY = y_canvas; } else { // mTouchMode == DrawingWindow.MODE_ZOOM float newDist = spacing( event ); if ( newDist > 16.0f && oldDist > 16.0f ) { float factor = newDist/oldDist; if ( factor > 0.05f && factor < 4.0f ) { changeZoom( factor ); oldDist = newDist; } } shiftByEvent( event ); } // ---------------------------------------- UP } else if (action == MotionEvent.ACTION_UP) { if ( mTouchMode == DrawingWindow.MODE_ZOOM ) { mTouchMode = DrawingWindow.MODE_MOVE; } else { float x_shift = x_canvas - mSaveX; // compute shift float y_shift = y_canvas - mSaveY; } } return true; } public void onClick(View view) { Button b = (Button)view; mDrawingSurface.stopDrawingThread(); if ( b == mBtnOk ) { mParent.doProjectedProfile( mName, mFrom, mAzimuth ); } dismiss(); } @Override public void onBackPressed() { mDrawingSurface.stopDrawingThread(); dismiss(); } }