mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-04 13:13:25 +03:00
0025195: Samples - add Java sample for Android 4.x
This commit is contained in:
@@ -0,0 +1,778 @@
|
||||
// Copyright (c) 2014 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
package com.opencascade.jnisample;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
|
||||
import android.text.Html;
|
||||
import android.text.Html.ImageGetter;
|
||||
import android.text.Spanned;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Display;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
//! Main activity
|
||||
public class OcctJniActivity extends Activity implements OnClickListener
|
||||
{
|
||||
|
||||
//! Auxiliary method to print temporary info messages
|
||||
public static void printShortInfo (Activity theActivity,
|
||||
CharSequence theInfo)
|
||||
{
|
||||
Context aCtx = theActivity.getApplicationContext();
|
||||
Toast aToast = Toast.makeText (aCtx, theInfo, Toast.LENGTH_LONG);
|
||||
aToast.show();
|
||||
}
|
||||
|
||||
//! Load single native library
|
||||
private static boolean loadLibVerbose (String theLibName,
|
||||
StringBuilder theLoadedInfo,
|
||||
StringBuilder theFailedInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.loadLibrary (theLibName);
|
||||
theLoadedInfo.append ("Info: native library \"");
|
||||
theLoadedInfo.append (theLibName);
|
||||
theLoadedInfo.append ("\" has been loaded\n");
|
||||
return true;
|
||||
}
|
||||
catch (java.lang.UnsatisfiedLinkError theError)
|
||||
{
|
||||
theFailedInfo.append ("Error: native library \"");
|
||||
theFailedInfo.append (theLibName);
|
||||
theFailedInfo.append ("\" is unavailable:\n " + theError.getMessage());
|
||||
return false;
|
||||
}
|
||||
catch (SecurityException theError)
|
||||
{
|
||||
theFailedInfo.append ("Error: native library \"");
|
||||
theFailedInfo.append (theLibName);
|
||||
theFailedInfo.append ("\" can not be loaded for security reasons:\n " + theError.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean wasNativesLoadCalled = false;
|
||||
public static boolean areNativeLoaded = false;
|
||||
public static String nativeLoaded = "";
|
||||
public static String nativeFailed = "";
|
||||
|
||||
//! Auxiliary method to load native libraries
|
||||
public boolean loadNatives()
|
||||
{
|
||||
if (wasNativesLoadCalled)
|
||||
{
|
||||
return areNativeLoaded;
|
||||
}
|
||||
wasNativesLoadCalled = true;
|
||||
StringBuilder aLoaded = new StringBuilder();
|
||||
StringBuilder aFailed = new StringBuilder();
|
||||
|
||||
// copy OCCT resources
|
||||
String aResFolder = getFilesDir().getAbsolutePath();
|
||||
copyAssetFolder (getAssets(), "Shaders", aResFolder + "/Shaders");
|
||||
copyAssetFolder (getAssets(), "SHMessage", aResFolder + "/SHMessage");
|
||||
copyAssetFolder (getAssets(), "XSMessage", aResFolder + "/XSMessage");
|
||||
copyAssetFolder (getAssets(), "TObj", aResFolder + "/TObj");
|
||||
copyAssetFolder (getAssets(), "UnitsAPI", aResFolder + "/UnitsAPI");
|
||||
|
||||
// C++ runtime
|
||||
loadLibVerbose ("gnustl_shared", aLoaded, aFailed);
|
||||
|
||||
// 3rd-parties
|
||||
loadLibVerbose ("freetype", aLoaded, aFailed);
|
||||
loadLibVerbose ("freeimage", aLoaded, aFailed);
|
||||
|
||||
if (// OCCT modeling
|
||||
!loadLibVerbose ("TKernel", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKMath", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKG2d", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKG3d", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKGeomBase", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKBRep", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKGeomAlgo", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKTopAlgo", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKShHealing", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKMesh", aLoaded, aFailed)
|
||||
// exchange
|
||||
|| !loadLibVerbose ("TKPrim", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKBO", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKBool", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKFillet", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKOffset", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKXSBase", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKIGES", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKSTEPBase", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKSTEPAttr", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKSTEP209", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKSTEP", aLoaded, aFailed)
|
||||
// OCCT Visualization
|
||||
|| !loadLibVerbose ("TKService", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKHLR", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKV3d", aLoaded, aFailed)
|
||||
|| !loadLibVerbose ("TKOpenGl", aLoaded, aFailed)
|
||||
// application code
|
||||
|| !loadLibVerbose ("TKJniSample", aLoaded, aFailed))
|
||||
{
|
||||
nativeLoaded = aLoaded.toString();
|
||||
nativeFailed = aFailed.toString();
|
||||
areNativeLoaded = false;
|
||||
//exitWithError (theActivity, "Broken apk?\n" + theFailedInfo);
|
||||
return false;
|
||||
}
|
||||
nativeLoaded = aLoaded.toString();
|
||||
areNativeLoaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Create activity
|
||||
@Override protected void onCreate (Bundle theBundle)
|
||||
{
|
||||
super.onCreate (theBundle);
|
||||
|
||||
boolean isLoaded = loadNatives();
|
||||
if (!isLoaded)
|
||||
{
|
||||
printShortInfo (this, nativeFailed);
|
||||
OcctJniLogger.postMessage (nativeLoaded + "\n" + nativeFailed);
|
||||
}
|
||||
|
||||
setContentView (R.layout.activity_main);
|
||||
|
||||
myOcctView = (OcctJniView )findViewById (R.id.custom_view);
|
||||
myMessageTextView = (TextView )findViewById (R.id.message_view);
|
||||
OcctJniLogger.setTextView (myMessageTextView);
|
||||
|
||||
createViewAndButtons (Configuration.ORIENTATION_LANDSCAPE);
|
||||
|
||||
myButtonPreferSize = defineButtonSize ((LinearLayout )findViewById (R.id.panel_menu));
|
||||
ImageButton aScrollBtn = (ImageButton )findViewById (R.id.scroll_btn);
|
||||
aScrollBtn.setY (myButtonPreferSize);
|
||||
aScrollBtn.setOnTouchListener (new View.OnTouchListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onTouch (View theView, MotionEvent theEvent)
|
||||
{
|
||||
return onScrollBtnTouch (theView, theEvent);
|
||||
}
|
||||
});
|
||||
|
||||
onConfigurationChanged (getResources().getConfiguration());
|
||||
|
||||
Intent anIntent = getIntent();
|
||||
Uri aDataUrl = anIntent != null ? anIntent.getData() : null;
|
||||
String aDataPath = aDataUrl != null ? aDataUrl.getPath() : "";
|
||||
myOcctView.open (aDataPath);
|
||||
myLastPath = aDataPath;
|
||||
}
|
||||
|
||||
//! Handle scroll events
|
||||
private boolean onScrollBtnTouch (View theView,
|
||||
MotionEvent theEvent)
|
||||
{
|
||||
switch (theEvent.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
{
|
||||
LinearLayout aPanelMenu = (LinearLayout )findViewById (R.id.panel_menu);
|
||||
boolean isLandscape = (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
|
||||
if (aPanelMenu.getVisibility() == View.VISIBLE)
|
||||
{
|
||||
aPanelMenu.setVisibility (View.GONE);
|
||||
if (!isLandscape)
|
||||
{
|
||||
((ImageButton )theView).setImageResource (R.drawable.open_p);
|
||||
theView.setY (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
((ImageButton )theView).setImageResource (R.drawable.open_l);
|
||||
theView.setX (0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aPanelMenu.setVisibility (View.VISIBLE);
|
||||
if (!isLandscape)
|
||||
{
|
||||
((ImageButton )theView).setImageResource (R.drawable.close_p);
|
||||
theView.setY (myButtonPreferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
((ImageButton )theView).setImageResource (R.drawable.close_l);
|
||||
theView.setX (myButtonPreferSize);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Initialize views and buttons
|
||||
private void createViewAndButtons (int theOrientation)
|
||||
{
|
||||
// open button
|
||||
ImageButton anOpenButton = (ImageButton )findViewById (R.id.open);
|
||||
anOpenButton.setOnClickListener (this);
|
||||
|
||||
// fit all
|
||||
ImageButton aFitAllButton = (ImageButton )findViewById (R.id.fit);
|
||||
aFitAllButton.setOnClickListener (this);
|
||||
aFitAllButton.setOnTouchListener (new View.OnTouchListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onTouch (View theView, MotionEvent theEvent)
|
||||
{
|
||||
return onTouchButton (theView, theEvent);
|
||||
}
|
||||
});
|
||||
|
||||
// message
|
||||
ImageButton aMessageButton = (ImageButton )findViewById (R.id.message);
|
||||
aMessageButton.setOnClickListener (this);
|
||||
|
||||
// info
|
||||
ImageButton anInfoButton = (ImageButton )findViewById (R.id.info);
|
||||
anInfoButton.setOnClickListener (this);
|
||||
|
||||
// font for text view
|
||||
TextView anInfoView = (TextView )findViewById (R.id.info_view);
|
||||
anInfoView.setTextSize (TypedValue.COMPLEX_UNIT_SP, 18);
|
||||
|
||||
// add submenu buttons
|
||||
createSubmenuBtn (R.id.view, R.id.view_group,
|
||||
Arrays.asList (R.id.proj_front, R.id.proj_top, R.id.proj_left,
|
||||
R.id.proj_back, R.id.proj_bottom, R.id.proj_right),
|
||||
Arrays.asList (R.drawable.proj_front, R.drawable.proj_top, R.drawable.proj_left,
|
||||
R.drawable.proj_back, R.drawable.proj_bottom, R.drawable.proj_right),
|
||||
4);
|
||||
}
|
||||
|
||||
@Override protected void onNewIntent (Intent theIntent)
|
||||
{
|
||||
super.onNewIntent (theIntent);
|
||||
setIntent (theIntent);
|
||||
}
|
||||
|
||||
@Override protected void onDestroy()
|
||||
{
|
||||
super.onDestroy();
|
||||
OcctJniLogger.setTextView (null);
|
||||
}
|
||||
|
||||
@Override protected void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
myOcctView.onPause();
|
||||
}
|
||||
|
||||
@Override protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
myOcctView.onResume();
|
||||
|
||||
Intent anIntent = getIntent();
|
||||
Uri aDataUrl = anIntent != null ? anIntent.getData() : null;
|
||||
String aDataPath = aDataUrl != null ? aDataUrl.getPath() : "";
|
||||
if (!aDataPath.equals (myLastPath))
|
||||
{
|
||||
myOcctView.open (aDataPath);
|
||||
myLastPath = aDataPath;
|
||||
}
|
||||
}
|
||||
|
||||
//! Copy folder from assets
|
||||
private boolean copyAssetFolder (AssetManager theAssetMgr,
|
||||
String theAssetFolder,
|
||||
String theFolderPathTo)
|
||||
{
|
||||
try
|
||||
{
|
||||
String[] aFiles = theAssetMgr.list (theAssetFolder);
|
||||
File aFolder = new File (theFolderPathTo);
|
||||
aFolder.mkdirs();
|
||||
boolean isOk = true;
|
||||
for (String aFileIter : aFiles)
|
||||
{
|
||||
if (aFileIter.contains ("."))
|
||||
{
|
||||
isOk &= copyAsset (theAssetMgr,
|
||||
theAssetFolder + "/" + aFileIter,
|
||||
theFolderPathTo + "/" + aFileIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
isOk &= copyAssetFolder (theAssetMgr,
|
||||
theAssetFolder + "/" + aFileIter,
|
||||
theFolderPathTo + "/" + aFileIter);
|
||||
}
|
||||
}
|
||||
return isOk;
|
||||
}
|
||||
catch (Exception theError)
|
||||
{
|
||||
theError.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//! Copy single file from assets
|
||||
private boolean copyAsset (AssetManager theAssetMgr,
|
||||
String thePathFrom,
|
||||
String thePathTo)
|
||||
{
|
||||
try
|
||||
{
|
||||
InputStream aStreamIn = theAssetMgr.open (thePathFrom);
|
||||
File aFileTo = new File (thePathTo);
|
||||
aFileTo.createNewFile();
|
||||
OutputStream aStreamOut = new FileOutputStream (thePathTo);
|
||||
copyStreamContent (aStreamIn, aStreamOut);
|
||||
aStreamIn.close();
|
||||
aStreamIn = null;
|
||||
aStreamOut.flush();
|
||||
aStreamOut.close();
|
||||
aStreamOut = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception theError)
|
||||
{
|
||||
theError.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//! Copy single file
|
||||
private static void copyStreamContent (InputStream theIn,
|
||||
OutputStream theOut) throws IOException
|
||||
{
|
||||
byte[] aBuffer = new byte[1024];
|
||||
int aNbReadBytes = 0;
|
||||
while ((aNbReadBytes = theIn.read (aBuffer)) != -1)
|
||||
{
|
||||
theOut.write (aBuffer, 0, aNbReadBytes);
|
||||
}
|
||||
}
|
||||
|
||||
//! Show/hide text view
|
||||
private void switchTextView (TextView theTextView,
|
||||
ImageButton theClickedBtn,
|
||||
boolean theToSwitchOn)
|
||||
{
|
||||
if (theTextView != null
|
||||
&& theTextView.getVisibility() == View.GONE
|
||||
&& theToSwitchOn)
|
||||
{
|
||||
theTextView.setVisibility (View.VISIBLE);
|
||||
theClickedBtn.setBackgroundColor (getResources().getColor(R.color.pressedBtnColor));
|
||||
setTextViewPosition (theTextView);
|
||||
}
|
||||
else
|
||||
{
|
||||
theTextView.setVisibility (View.GONE);
|
||||
theClickedBtn.setBackgroundColor (getResources().getColor (R.color.btnColor));
|
||||
}
|
||||
}
|
||||
|
||||
//! Setup text view position
|
||||
private void setTextViewPosition (TextView theTextView)
|
||||
{
|
||||
if (theTextView.getVisibility() != View.VISIBLE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
|
||||
{
|
||||
theTextView.setX (myButtonPreferSize);
|
||||
theTextView.setY (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
theTextView.setX (0);
|
||||
theTextView.setY (myButtonPreferSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick (View theButton)
|
||||
{
|
||||
ImageButton aClickedBtn = (ImageButton )theButton;
|
||||
switch (aClickedBtn.getId())
|
||||
{
|
||||
case R.id.message:
|
||||
{
|
||||
switchTextView ((TextView )findViewById (R.id.info_view),
|
||||
(ImageButton )findViewById (R.id.info), false);
|
||||
switchTextView (myMessageTextView, aClickedBtn, true);
|
||||
return;
|
||||
}
|
||||
case R.id.info:
|
||||
{
|
||||
String aText = getString (R.string.info_html);
|
||||
aText = String.format (aText, cppOcctMajorVersion(), cppOcctMinorVersion(), cppOcctMicroVersion());
|
||||
Spanned aSpanned = Html.fromHtml (aText, new ImageGetter()
|
||||
{
|
||||
@Override
|
||||
public Drawable getDrawable (String theSource)
|
||||
{
|
||||
Resources aResources = getResources();
|
||||
int anId = aResources.getIdentifier (theSource, "drawable", getPackageName());
|
||||
Drawable aRes = aResources.getDrawable (anId);
|
||||
aRes.setBounds (0, 0, aRes.getIntrinsicWidth(), aRes.getIntrinsicHeight());
|
||||
return aRes;
|
||||
}
|
||||
}, null);
|
||||
|
||||
TextView anInfoView = (TextView )findViewById (R.id.info_view);
|
||||
anInfoView.setText (aSpanned);
|
||||
switchTextView (myMessageTextView, (ImageButton ) findViewById (R.id.message), false);
|
||||
switchTextView (anInfoView, aClickedBtn, true);
|
||||
return;
|
||||
}
|
||||
case R.id.fit:
|
||||
{
|
||||
myOcctView.fitAll();
|
||||
return;
|
||||
}
|
||||
case R.id.proj_front:
|
||||
{
|
||||
myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Xpos);
|
||||
return;
|
||||
}
|
||||
case R.id.proj_left:
|
||||
{
|
||||
myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Yneg);
|
||||
return;
|
||||
}
|
||||
case R.id.proj_top:
|
||||
{
|
||||
myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Zpos);
|
||||
return;
|
||||
}
|
||||
case R.id.proj_back:
|
||||
{
|
||||
myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Xneg);
|
||||
return;
|
||||
}
|
||||
case R.id.proj_right:
|
||||
{
|
||||
myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Ypos);
|
||||
return;
|
||||
}
|
||||
case R.id.proj_bottom:
|
||||
{
|
||||
myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Zneg);
|
||||
return;
|
||||
}
|
||||
case R.id.open:
|
||||
{
|
||||
File aPath = Environment.getExternalStorageDirectory();
|
||||
aClickedBtn.setBackgroundColor (getResources().getColor(R.color.pressedBtnColor));
|
||||
if (myFileOpenDialog == null)
|
||||
{
|
||||
myFileOpenDialog = new OcctJniFileDialog (this, aPath);
|
||||
myFileOpenDialog.setFileEndsWith (".brep");
|
||||
myFileOpenDialog.setFileEndsWith (".rle");
|
||||
myFileOpenDialog.setFileEndsWith (".iges");
|
||||
myFileOpenDialog.setFileEndsWith (".igs");
|
||||
myFileOpenDialog.setFileEndsWith (".step");
|
||||
myFileOpenDialog.setFileEndsWith (".stp");
|
||||
myFileOpenDialog.addFileListener (new OcctJniFileDialog.FileSelectedListener()
|
||||
{
|
||||
public void fileSelected (File theFile)
|
||||
{
|
||||
if (theFile != null && myOcctView != null)
|
||||
{
|
||||
myOcctView.open (theFile.getPath());
|
||||
}
|
||||
}
|
||||
});
|
||||
myFileOpenDialog.addDialogDismissedListener (new OcctJniFileDialog.DialogDismissedListener()
|
||||
{
|
||||
@Override
|
||||
public void dialogDismissed()
|
||||
{
|
||||
ImageButton openButton = (ImageButton )findViewById (R.id.open);
|
||||
openButton.setBackgroundColor (getResources().getColor(R.color.btnColor));
|
||||
}
|
||||
});
|
||||
}
|
||||
myFileOpenDialog.showDialog();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createSubmenuBtn (int theParentBtnId,
|
||||
int theParentLayoutId,
|
||||
final List<Integer> theNewButtonIds,
|
||||
final List<Integer> theNewButtonImageIds,
|
||||
int thePosition)
|
||||
{
|
||||
int aPosInList = 0;
|
||||
final ImageButton aParentBtn = (ImageButton )findViewById (theParentBtnId);
|
||||
|
||||
ViewGroup.LayoutParams aParams = null;
|
||||
LinearLayout parentLayout = (LinearLayout ) findViewById (theParentLayoutId);
|
||||
for (Integer newButtonId : theNewButtonIds)
|
||||
{
|
||||
ImageButton aNewButton = (ImageButton )findViewById (newButtonId);
|
||||
if (aNewButton == null)
|
||||
{
|
||||
aNewButton = (ImageButton )new ImageButton (this);
|
||||
aNewButton.setId (newButtonId);
|
||||
aNewButton.setImageResource (theNewButtonImageIds.get (aPosInList));
|
||||
aNewButton.setLayoutParams (aParams);
|
||||
parentLayout.addView (aNewButton);
|
||||
}
|
||||
|
||||
aNewButton.setOnClickListener (this);
|
||||
aNewButton.setVisibility (View.GONE);
|
||||
|
||||
aNewButton.setOnTouchListener (new View.OnTouchListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onTouch (View theView, MotionEvent theEvent)
|
||||
{
|
||||
return onTouchButton (theView, theEvent);
|
||||
}
|
||||
});
|
||||
++aPosInList;
|
||||
}
|
||||
|
||||
if (aParentBtn != null)
|
||||
{
|
||||
aParentBtn.setOnTouchListener (null);
|
||||
aParentBtn.setOnTouchListener (new View.OnTouchListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onTouch (View theView, MotionEvent theEvent)
|
||||
{
|
||||
if (theEvent.getAction () == MotionEvent.ACTION_DOWN)
|
||||
{
|
||||
Boolean isVisible = false;
|
||||
for (Integer aNewButtonId : theNewButtonIds)
|
||||
{
|
||||
ImageButton anBtn = (ImageButton )findViewById (aNewButtonId);
|
||||
if (anBtn != null)
|
||||
{
|
||||
if (anBtn.getVisibility() == View.GONE)
|
||||
{
|
||||
anBtn.setVisibility (View.VISIBLE);
|
||||
isVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
anBtn.setVisibility (View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
aParentBtn.setBackgroundColor (!isVisible ? getResources().getColor(R.color.btnColor) : getResources().getColor(R.color.pressedBtnColor));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//! Implements onTouch functionality
|
||||
private boolean onTouchButton (View theView,
|
||||
MotionEvent theEvent)
|
||||
{
|
||||
switch (theEvent.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
((ImageButton )theView).setBackgroundColor (getResources().getColor (R.color.pressedBtnColor));
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
((ImageButton )theView).setBackgroundColor (getResources().getColor (R.color.btnColor));
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Handle configuration change event
|
||||
@Override
|
||||
public void onConfigurationChanged (Configuration theNewConfig)
|
||||
{
|
||||
super.onConfigurationChanged (theNewConfig);
|
||||
LinearLayout aLayoutPanelMenu = (LinearLayout )findViewById (R.id.panel_menu);
|
||||
LayoutParams aPanelMenuLayoutParams = aLayoutPanelMenu.getLayoutParams();
|
||||
|
||||
LinearLayout aLayoutViewGroup = (LinearLayout )findViewById (R.id.view_group);
|
||||
LayoutParams aViewGroupLayoutParams = aLayoutViewGroup.getLayoutParams();
|
||||
ImageButton aScrollBtn = (ImageButton )findViewById (R.id.scroll_btn);
|
||||
LayoutParams aScrollBtnLayoutParams = aScrollBtn.getLayoutParams();
|
||||
|
||||
myButtonPreferSize = defineButtonSize ((LinearLayout )findViewById (R.id.panel_menu));
|
||||
defineButtonSize ((LinearLayout )findViewById (R.id.view_group));
|
||||
|
||||
switch (theNewConfig.orientation)
|
||||
{
|
||||
case Configuration.ORIENTATION_PORTRAIT:
|
||||
{
|
||||
setHorizontal (aLayoutPanelMenu, aPanelMenuLayoutParams);
|
||||
setHorizontal (aLayoutViewGroup, aViewGroupLayoutParams);
|
||||
aLayoutViewGroup.setGravity (Gravity.BOTTOM);
|
||||
|
||||
aScrollBtnLayoutParams.height = LayoutParams.WRAP_CONTENT;
|
||||
aScrollBtnLayoutParams.width = LayoutParams.MATCH_PARENT;
|
||||
aScrollBtn.setLayoutParams (aScrollBtnLayoutParams);
|
||||
if (aLayoutPanelMenu.getVisibility() == View.VISIBLE)
|
||||
{
|
||||
aScrollBtn.setImageResource (R.drawable.close_p);
|
||||
aScrollBtn.setY (myButtonPreferSize);
|
||||
aScrollBtn.setX (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
aScrollBtn.setImageResource (R.drawable.open_p);
|
||||
aScrollBtn.setY (0);
|
||||
aScrollBtn.setX (0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Configuration.ORIENTATION_LANDSCAPE:
|
||||
{
|
||||
setVertical (aLayoutPanelMenu, aPanelMenuLayoutParams);
|
||||
setVertical (aLayoutViewGroup, aViewGroupLayoutParams);
|
||||
aLayoutViewGroup.setGravity (Gravity.RIGHT);
|
||||
|
||||
aScrollBtnLayoutParams.height = LayoutParams.MATCH_PARENT;
|
||||
aScrollBtnLayoutParams.width = LayoutParams.WRAP_CONTENT;
|
||||
aScrollBtn.setLayoutParams (aScrollBtnLayoutParams);
|
||||
if (aLayoutPanelMenu.getVisibility() == View.VISIBLE)
|
||||
{
|
||||
aScrollBtn.setImageResource (R.drawable.close_l);
|
||||
aScrollBtn.setX (myButtonPreferSize);
|
||||
aScrollBtn.setY (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
aScrollBtn.setImageResource (R.drawable.open_l);
|
||||
aScrollBtn.setY (0);
|
||||
aScrollBtn.setX (0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
setTextViewPosition (myMessageTextView);
|
||||
setTextViewPosition ((TextView )findViewById (R.id.info_view));
|
||||
}
|
||||
|
||||
private void setHorizontal (LinearLayout theLayout,
|
||||
LayoutParams theLayoutParams)
|
||||
{
|
||||
theLayout.setOrientation (LinearLayout.HORIZONTAL);
|
||||
theLayoutParams.height = LayoutParams.WRAP_CONTENT;
|
||||
theLayoutParams.width = LayoutParams.MATCH_PARENT;
|
||||
theLayout.setLayoutParams (theLayoutParams);
|
||||
}
|
||||
|
||||
private void setVertical (LinearLayout theLayout,
|
||||
LayoutParams theLayoutParams)
|
||||
{
|
||||
theLayout.setOrientation (LinearLayout.VERTICAL);
|
||||
theLayoutParams.height = LayoutParams.MATCH_PARENT;
|
||||
theLayoutParams.width = LayoutParams.WRAP_CONTENT;
|
||||
theLayout.setLayoutParams (theLayoutParams);
|
||||
}
|
||||
|
||||
//! Define button size
|
||||
private int defineButtonSize (LinearLayout theLayout)
|
||||
{
|
||||
boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
|
||||
Display aDisplay = getWindowManager().getDefaultDisplay();
|
||||
Point aDispPnt = new Point();
|
||||
aDisplay.getSize (aDispPnt);
|
||||
|
||||
int aNbChildren = theLayout.getChildCount();
|
||||
int aHeight = aDispPnt.y / aNbChildren;
|
||||
int aWidth = aDispPnt.x / aNbChildren;
|
||||
int aResultSize = 0;
|
||||
for (int aChildIter = 0; aChildIter < aNbChildren; ++aChildIter)
|
||||
{
|
||||
View aView = theLayout.getChildAt (aChildIter);
|
||||
if (aView instanceof ImageButton)
|
||||
{
|
||||
ImageButton aButton = (ImageButton )aView;
|
||||
if (isLandscape)
|
||||
{
|
||||
aButton.setMinimumWidth (aHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
aButton.setMinimumHeight (aWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isLandscape)
|
||||
{
|
||||
aResultSize = aHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
aResultSize = aWidth;
|
||||
}
|
||||
return aResultSize;
|
||||
}
|
||||
|
||||
//! OCCT major version
|
||||
private native long cppOcctMajorVersion();
|
||||
|
||||
//! OCCT minor version
|
||||
private native long cppOcctMinorVersion();
|
||||
|
||||
//! OCCT micro version
|
||||
private native long cppOcctMicroVersion();
|
||||
|
||||
private OcctJniView myOcctView;
|
||||
private TextView myMessageTextView;
|
||||
private String myLastPath;
|
||||
private OcctJniFileDialog myFileOpenDialog;
|
||||
private int myButtonPreferSize = 65;
|
||||
|
||||
}
|
@@ -0,0 +1,376 @@
|
||||
// Copyright (c) 2014 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
package com.opencascade.jnisample;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.opencascade.jnisample.ListenerList.FireHandler;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Color;
|
||||
import android.os.Environment;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Spinner;
|
||||
|
||||
//! Simple open file dialog
|
||||
public class OcctJniFileDialog
|
||||
{
|
||||
|
||||
public enum DialogMode
|
||||
{
|
||||
FileOpen, FileExport, FileSave
|
||||
}
|
||||
|
||||
private static final String PARENT_DIR = "..";
|
||||
private String[] myFileList;
|
||||
private File myCurrentPath;
|
||||
private DialogMode myDialogMode = DialogMode.FileOpen;
|
||||
|
||||
private ListenerList<FileSelectedListener> myFileListenerList = new ListenerList<OcctJniFileDialog.FileSelectedListener>();
|
||||
private ListenerList<DialogDismissedListener> myDialogDismissedList = new ListenerList<DialogDismissedListener>();
|
||||
private final Activity myActivity;
|
||||
private List<String> myFileEndsWith;
|
||||
private EditText myFileNameInput;
|
||||
private Spinner myFileExtSpinner;
|
||||
int myCurrentExtPositionInList = 0;
|
||||
|
||||
public interface FileSelectedListener
|
||||
{
|
||||
void fileSelected (File theFile);
|
||||
}
|
||||
|
||||
public interface DialogDismissedListener
|
||||
{
|
||||
void dialogDismissed();
|
||||
}
|
||||
|
||||
//! Main constructor.
|
||||
public OcctJniFileDialog (Activity theActivity,
|
||||
File thePath)
|
||||
{
|
||||
myActivity = theActivity;
|
||||
if (!thePath.exists())
|
||||
{
|
||||
thePath = Environment.getExternalStorageDirectory();
|
||||
}
|
||||
loadFileList (thePath);
|
||||
}
|
||||
|
||||
//! Create new dialog
|
||||
public Dialog createFileDialog()
|
||||
{
|
||||
final Object[] anObjWrapper = new Object[1];
|
||||
Dialog aDialog = null;
|
||||
AlertDialog.Builder aBuilder = new AlertDialog.Builder (myActivity);
|
||||
|
||||
aBuilder.setTitle (myCurrentPath.getPath());
|
||||
LinearLayout aTitleLayout = new LinearLayout (myActivity);
|
||||
aTitleLayout.setLayoutParams (new LinearLayout.LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
|
||||
aTitleLayout.setOrientation (LinearLayout.VERTICAL);
|
||||
|
||||
ListView list = new ListView (myActivity);
|
||||
list.setScrollingCacheEnabled(false);
|
||||
list.setBackgroundColor (Color.parseColor ("#33B5E5"));
|
||||
|
||||
list.setAdapter (new ArrayAdapter<String> (myActivity, android.R.layout.select_dialog_item, myFileList));
|
||||
list.setOnItemClickListener (new AdapterView.OnItemClickListener ()
|
||||
{
|
||||
|
||||
public void onItemClick (AdapterView<?> arg0, View view, int pos, long id)
|
||||
{
|
||||
String fileChosen = myFileList[pos];
|
||||
File aChosenFile = getChosenFile (fileChosen);
|
||||
if (aChosenFile.isDirectory())
|
||||
{
|
||||
loadFileList (aChosenFile);
|
||||
((Dialog )anObjWrapper[0]).cancel();
|
||||
((Dialog )anObjWrapper[0]).dismiss();
|
||||
showDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (myDialogMode == DialogMode.FileOpen)
|
||||
{
|
||||
((Dialog )anObjWrapper[0]).cancel();
|
||||
((Dialog )anObjWrapper[0]).dismiss();
|
||||
fireFileSelectedEvent (aChosenFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
myFileNameInput.setText (aChosenFile.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
list.setLayoutParams (new LinearLayout.LayoutParams (LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, 0.6f));
|
||||
aTitleLayout.addView (list);
|
||||
|
||||
if (myDialogMode == DialogMode.FileSave
|
||||
|| myDialogMode == DialogMode.FileExport)
|
||||
{
|
||||
myFileNameInput = new EditText (myActivity);
|
||||
myFileExtSpinner = new Spinner (myActivity);
|
||||
ArrayAdapter<CharSequence> adapter = null;
|
||||
if (myDialogMode == DialogMode.FileExport)
|
||||
{
|
||||
adapter = ArrayAdapter.createFromResource (myActivity, R.array.ext_to_exp,
|
||||
android.R.layout.simple_spinner_item);
|
||||
}
|
||||
else
|
||||
{
|
||||
adapter = ArrayAdapter.createFromResource (myActivity, R.array.ext_to_save,
|
||||
android.R.layout.simple_spinner_item);
|
||||
}
|
||||
// Specify the layout to use when the list of choices appears
|
||||
adapter.setDropDownViewResource (android.R.layout.simple_spinner_dropdown_item);
|
||||
// Apply the adapter to the spinner
|
||||
myFileExtSpinner.setAdapter (adapter);
|
||||
myFileExtSpinner.setSelection (myCurrentExtPositionInList);
|
||||
|
||||
myFileExtSpinner.setOnItemSelectedListener (new AdapterView.OnItemSelectedListener()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void onNothingSelected (AdapterView<?> theParentView)
|
||||
{
|
||||
// your code here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected (AdapterView<?> theParent, View theView, int thePosition, long theId)
|
||||
{
|
||||
if (myCurrentExtPositionInList != thePosition)
|
||||
{
|
||||
myCurrentExtPositionInList = thePosition;
|
||||
setFileEndsWith (Arrays.asList (myFileExtSpinner.getSelectedItem().toString()));
|
||||
loadFileList (myCurrentPath);
|
||||
((Dialog )anObjWrapper[0]).cancel();
|
||||
((Dialog )anObjWrapper[0]).dismiss();
|
||||
showDialog();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
myFileExtSpinner.setLayoutParams (new LinearLayout.LayoutParams (LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.WRAP_CONTENT, 0.2f));
|
||||
// titleLayout.addView(fileExtSpinner);
|
||||
myFileNameInput.setLayoutParams (new LinearLayout.LayoutParams (LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.WRAP_CONTENT, 0.2f));
|
||||
LinearLayout aControlsView = new LinearLayout (myActivity);
|
||||
|
||||
aControlsView.addView (myFileNameInput);
|
||||
aControlsView.addView (myFileExtSpinner);
|
||||
|
||||
aTitleLayout.addView (aControlsView);
|
||||
aBuilder.setView (aTitleLayout);
|
||||
aBuilder.setPositiveButton ("OK", new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick (DialogInterface theDialog, int theWhich)
|
||||
{
|
||||
if (theWhich >= 0)
|
||||
{
|
||||
String aFileChosen = myFileList[theWhich];
|
||||
File aChosenFile = getChosenFile (aFileChosen);
|
||||
fireFileSelectedEvent (aChosenFile);
|
||||
}
|
||||
}
|
||||
}).setNegativeButton ("Cancel", null);
|
||||
}
|
||||
else
|
||||
{
|
||||
aBuilder.setNegativeButton ("Cancel", null);
|
||||
}
|
||||
|
||||
aBuilder.setView (aTitleLayout);
|
||||
|
||||
aDialog = aBuilder.show();
|
||||
aDialog.setOnDismissListener (new DialogInterface.OnDismissListener()
|
||||
{
|
||||
@Override
|
||||
public void onDismiss (DialogInterface theDialog)
|
||||
{
|
||||
fireDialogDismissedEvent();
|
||||
}
|
||||
});
|
||||
anObjWrapper[0] = aDialog;
|
||||
return aDialog;
|
||||
}
|
||||
|
||||
public void addFileListener (FileSelectedListener theListener)
|
||||
{
|
||||
myFileListenerList.add (theListener);
|
||||
}
|
||||
|
||||
public void addDialogDismissedListener (DialogDismissedListener theListener)
|
||||
{
|
||||
myDialogDismissedList.add (theListener);
|
||||
}
|
||||
|
||||
//! Show file dialog
|
||||
public void showDialog()
|
||||
{
|
||||
createFileDialog().show();
|
||||
}
|
||||
|
||||
private void fireFileSelectedEvent (final File theFile)
|
||||
{
|
||||
myFileListenerList.fireEvent (new FireHandler<OcctJniFileDialog.FileSelectedListener>()
|
||||
{
|
||||
public void fireEvent (FileSelectedListener theListener)
|
||||
{
|
||||
theListener.fileSelected (theFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fireDialogDismissedEvent()
|
||||
{
|
||||
myDialogDismissedList.fireEvent (new FireHandler<OcctJniFileDialog.DialogDismissedListener>()
|
||||
{
|
||||
public void fireEvent (DialogDismissedListener theListener)
|
||||
{
|
||||
theListener.dialogDismissed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadFileList (File thePath)
|
||||
{
|
||||
myCurrentPath = thePath;
|
||||
List<String> aList = new ArrayList<String>();
|
||||
if (thePath.exists())
|
||||
{
|
||||
if (thePath.getParentFile() != null)
|
||||
{
|
||||
aList.add (PARENT_DIR);
|
||||
}
|
||||
FilenameFilter aFilter = new FilenameFilter()
|
||||
{
|
||||
public boolean accept (File theDir, String theFilename)
|
||||
{
|
||||
File aSel = new File (theDir, theFilename);
|
||||
if (!aSel.canRead())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
boolean isEndWith = false;
|
||||
if (myFileEndsWith != null)
|
||||
{
|
||||
for (String aFileExtIter : myFileEndsWith)
|
||||
{
|
||||
if (theFilename.toLowerCase().endsWith (aFileExtIter))
|
||||
{
|
||||
isEndWith = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isEndWith || aSel.isDirectory();
|
||||
}
|
||||
};
|
||||
String[] aFileList1 = thePath.list (aFilter);
|
||||
if (aFileList1 != null)
|
||||
{
|
||||
for (String aFileIter : aFileList1)
|
||||
{
|
||||
aList.add (aFileIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
myFileList = (String[] )aList.toArray (new String[] {});
|
||||
}
|
||||
|
||||
private File getChosenFile (String theFileChosen)
|
||||
{
|
||||
if (theFileChosen.equals (PARENT_DIR))
|
||||
return myCurrentPath.getParentFile();
|
||||
else
|
||||
return new File (myCurrentPath, theFileChosen);
|
||||
}
|
||||
|
||||
public void setFileEndsWith (String fileEndsWith)
|
||||
{
|
||||
if (myFileEndsWith == null)
|
||||
{
|
||||
myFileEndsWith = new ArrayList<String>();
|
||||
}
|
||||
if (myFileEndsWith.indexOf (fileEndsWith) == -1)
|
||||
{
|
||||
myFileEndsWith.add (fileEndsWith);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFileEndsWith (List<String> theFileEndsWith)
|
||||
{
|
||||
myFileEndsWith = theFileEndsWith;
|
||||
}
|
||||
|
||||
public DialogMode DialogMode()
|
||||
{
|
||||
return myDialogMode;
|
||||
}
|
||||
|
||||
public void DialogMode (DialogMode theMode)
|
||||
{
|
||||
myDialogMode = theMode;
|
||||
}
|
||||
}
|
||||
|
||||
class ListenerList<L>
|
||||
{
|
||||
private List<L> myListenerList = new ArrayList<L>();
|
||||
|
||||
public interface FireHandler<L>
|
||||
{
|
||||
void fireEvent (L theListener);
|
||||
}
|
||||
|
||||
public void add (L theListener)
|
||||
{
|
||||
myListenerList.add (theListener);
|
||||
}
|
||||
|
||||
public void fireEvent (FireHandler<L> theFireHandler)
|
||||
{
|
||||
List<L> aCopy = new ArrayList<L> (myListenerList);
|
||||
for (L anIter : aCopy)
|
||||
{
|
||||
theFireHandler.fireEvent (anIter);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove (L theListener)
|
||||
{
|
||||
myListenerList.remove (theListener);
|
||||
}
|
||||
|
||||
public List<L> getListenerList()
|
||||
{
|
||||
return myListenerList;
|
||||
}
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2014 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
package com.opencascade.jnisample;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
|
||||
//! Auxiliary class for logging messages
|
||||
public class OcctJniLogger
|
||||
{
|
||||
|
||||
//! Setup text view
|
||||
public static void setTextView (TextView theTextView)
|
||||
{
|
||||
if (myTextView != null)
|
||||
{
|
||||
myLog = myTextView.getText().toString();
|
||||
}
|
||||
|
||||
myTextView = theTextView;
|
||||
if (myTextView != null)
|
||||
{
|
||||
myTextView.setText (myLog);
|
||||
myLog = "";
|
||||
}
|
||||
}
|
||||
|
||||
//! Interface implementation
|
||||
public static void postMessage (String theText)
|
||||
{
|
||||
final String aCopy = new String (theText);
|
||||
Log.e (myTag, theText);
|
||||
|
||||
myMutex.lock();
|
||||
final TextView aView = myTextView;
|
||||
if (aView == null)
|
||||
{
|
||||
myLog += aCopy;
|
||||
myMutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
aView.post (new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
aView.setText (aView.getText() + aCopy + "\n");
|
||||
}
|
||||
});
|
||||
myMutex.unlock();
|
||||
}
|
||||
|
||||
private static final String myTag = "occtJniViewer";
|
||||
private static final ReentrantLock myMutex = new ReentrantLock (true);
|
||||
private static TextView myTextView = null;
|
||||
private static String myLog = "";
|
||||
|
||||
}
|
@@ -0,0 +1,218 @@
|
||||
// Copyright (c) 2014 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
package com.opencascade.jnisample;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
import android.opengl.GLSurfaceView;
|
||||
|
||||
//! Wrapper for C++ OCCT viewer.
|
||||
public class OcctJniRenderer implements GLSurfaceView.Renderer
|
||||
{
|
||||
|
||||
//! Wrapper for V3d_TypeOfOrientation
|
||||
enum TypeOfOrientation
|
||||
{
|
||||
Xpos, // front
|
||||
Ypos, // left
|
||||
Zpos, // top
|
||||
Xneg, // back
|
||||
Yneg, // right
|
||||
Zneg // bottom
|
||||
};
|
||||
|
||||
//! Empty constructor.
|
||||
OcctJniRenderer()
|
||||
{
|
||||
if (OcctJniActivity.areNativeLoaded)
|
||||
{
|
||||
myCppViewer = cppCreate();
|
||||
}
|
||||
}
|
||||
|
||||
//! Open file.
|
||||
public void open (String thePath)
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppOpen (myCppViewer, thePath);
|
||||
}
|
||||
}
|
||||
|
||||
//! Update viewer.
|
||||
public void onDrawFrame (GL10 theGl)
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppRedraw (myCppViewer);
|
||||
}
|
||||
}
|
||||
|
||||
//! (re)initialize viewer.
|
||||
public void onSurfaceChanged (GL10 theGl, int theWidth, int theHeight)
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppResize (myCppViewer, theWidth, theHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public void onSurfaceCreated (GL10 theGl, EGLConfig theEglConfig)
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppInit (myCppViewer);
|
||||
}
|
||||
}
|
||||
|
||||
//! Initialize rotation (remember first point position)
|
||||
public void onStartRotation (int theStartX, int theStartY)
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppStartRotation (myCppViewer, theStartX, theStartY);
|
||||
}
|
||||
}
|
||||
|
||||
//! Perform rotation (relative to first point)
|
||||
public void onRotation (int theX, int theY)
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppOnRotation (myCppViewer, theX, theY);
|
||||
}
|
||||
}
|
||||
|
||||
//! Perform panning
|
||||
public void onPanning (int theDX, int theDY)
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppOnPanning (myCppViewer, theDX, theDY);
|
||||
}
|
||||
}
|
||||
|
||||
//! Perform selection
|
||||
public void onClick (int theX, int theY)
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppOnClick (myCppViewer, theX, theY);
|
||||
}
|
||||
}
|
||||
|
||||
//! Stop previously active action (e.g. discard first rotation point)
|
||||
public void onStopAction()
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppStopAction (myCppViewer);
|
||||
}
|
||||
}
|
||||
|
||||
//! Fit All
|
||||
public void fitAll()
|
||||
{
|
||||
if (myCppViewer != 0)
|
||||
{
|
||||
cppFitAll (myCppViewer);
|
||||
}
|
||||
}
|
||||
|
||||
//! Move camera
|
||||
public void setProj (TypeOfOrientation theProj)
|
||||
{
|
||||
if (myCppViewer == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (theProj)
|
||||
{
|
||||
case Xpos: cppSetXposProj (myCppViewer); break;
|
||||
case Ypos: cppSetYposProj (myCppViewer); break;
|
||||
case Zpos: cppSetZposProj (myCppViewer); break;
|
||||
case Xneg: cppSetXnegProj (myCppViewer); break;
|
||||
case Yneg: cppSetYnegProj (myCppViewer); break;
|
||||
case Zneg: cppSetZnegProj (myCppViewer); break;
|
||||
}
|
||||
}
|
||||
|
||||
//! Post message to the text view.
|
||||
public void postMessage (String theText)
|
||||
{
|
||||
OcctJniLogger.postMessage (theText);
|
||||
}
|
||||
|
||||
//! Create instance of C++ class
|
||||
private native long cppCreate();
|
||||
|
||||
//! Destroy instance of C++ class
|
||||
private native void cppDestroy (long theCppPtr);
|
||||
|
||||
//! Initialize OCCT viewer (steal OpenGL ES context bound to this thread)
|
||||
private native void cppInit (long theCppPtr);
|
||||
|
||||
//! Resize OCCT viewer
|
||||
private native void cppResize (long theCppPtr, int theWidth, int theHeight);
|
||||
|
||||
//! Open CAD file
|
||||
private native void cppOpen (long theCppPtr, String thePath);
|
||||
|
||||
//! Handle detection in the viewer
|
||||
private native void cppMoveTo (long theCppPtr, int theX, int theY);
|
||||
|
||||
//! Redraw OCCT viewer
|
||||
private native void cppRedraw (long theCppPtr);
|
||||
|
||||
//! Fit All
|
||||
private native void cppFitAll (long theCppPtr);
|
||||
|
||||
//! Move camera
|
||||
private native void cppSetXposProj (long theCppPtr);
|
||||
|
||||
//! Move camera
|
||||
private native void cppSetYposProj (long theCppPtr);
|
||||
|
||||
//! Move camera
|
||||
private native void cppSetZposProj (long theCppPtr);
|
||||
|
||||
//! Move camera
|
||||
private native void cppSetXnegProj (long theCppPtr);
|
||||
|
||||
//! Move camera
|
||||
private native void cppSetYnegProj (long theCppPtr);
|
||||
|
||||
//! Move camera
|
||||
private native void cppSetZnegProj (long theCppPtr);
|
||||
|
||||
//! Initialize rotation
|
||||
private native void cppStartRotation (long theCppPtr, int theStartX, int theStartY);
|
||||
|
||||
//! Perform rotation
|
||||
private native void cppOnRotation (long theCppPtr, int theX, int theY);
|
||||
|
||||
//! Perform panning
|
||||
private native void cppOnPanning (long theCppPtr, int theDX, int theDY);
|
||||
|
||||
//! Perform selection
|
||||
private native void cppOnClick (long theCppPtr, int theX, int theY);
|
||||
|
||||
//! Stop action (rotation / panning / scaling)
|
||||
private native void cppStopAction (long theCppPtr);
|
||||
|
||||
private long myCppViewer = 0; //!< pointer to c++ class instance
|
||||
|
||||
}
|
@@ -0,0 +1,332 @@
|
||||
// Copyright (c) 2014 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
package com.opencascade.jnisample;
|
||||
|
||||
import android.app.ActionBar.LayoutParams;
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLContext;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
|
||||
//! OpenGL ES 2.0+ view.
|
||||
//! Performs rendering in parallel thread.
|
||||
class OcctJniView extends GLSurfaceView
|
||||
{
|
||||
|
||||
// ! Default constructor.
|
||||
public OcctJniView (Context theContext,
|
||||
AttributeSet theAttrs)
|
||||
{
|
||||
super (theContext, theAttrs);
|
||||
|
||||
setPreserveEGLContextOnPause (true);
|
||||
setEGLContextFactory (new ContextFactory());
|
||||
setEGLConfigChooser (new ConfigChooser());
|
||||
|
||||
RelativeLayout.LayoutParams aLParams = new RelativeLayout.LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
aLParams.addRule (RelativeLayout.ALIGN_TOP);
|
||||
|
||||
myRenderer = new OcctJniRenderer();
|
||||
setRenderer (myRenderer);
|
||||
}
|
||||
|
||||
//! Open file.
|
||||
public void open (String thePath)
|
||||
{
|
||||
final String aPath = thePath;
|
||||
queueEvent (new Runnable() { public void run() { myRenderer.open (aPath); }});
|
||||
}
|
||||
|
||||
//! Create OpenGL ES 2.0+ context
|
||||
private static class ContextFactory implements GLSurfaceView.EGLContextFactory
|
||||
{
|
||||
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
public EGLContext createContext (EGL10 theEgl,
|
||||
EGLDisplay theEglDisplay,
|
||||
EGLConfig theEglConfig)
|
||||
{
|
||||
if (theEglConfig == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// reset EGL errors stack
|
||||
int anError = EGL10.EGL_SUCCESS;
|
||||
while ((anError = theEgl.eglGetError()) != EGL10.EGL_SUCCESS) {}
|
||||
|
||||
int[] anAttribs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
|
||||
EGLContext aEglContext = theEgl.eglCreateContext (theEglDisplay, theEglConfig, EGL10.EGL_NO_CONTEXT, anAttribs);
|
||||
|
||||
while ((anError = theEgl.eglGetError()) != EGL10.EGL_SUCCESS)
|
||||
{
|
||||
OcctJniLogger.postMessage ("Error: eglCreateContext() " + String.format ("0x%x", anError));
|
||||
}
|
||||
return aEglContext;
|
||||
}
|
||||
|
||||
public void destroyContext (EGL10 theEgl,
|
||||
EGLDisplay theEglDisplay,
|
||||
EGLContext theEglContext)
|
||||
{
|
||||
theEgl.eglDestroyContext (theEglDisplay, theEglContext);
|
||||
}
|
||||
}
|
||||
|
||||
//! Search for RGB24 config with depth and stencil buffers
|
||||
private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser
|
||||
{
|
||||
//! Reset EGL errors stack
|
||||
private void popEglErrors (EGL10 theEgl)
|
||||
{
|
||||
int anError = EGL10.EGL_SUCCESS;
|
||||
while ((anError = theEgl.eglGetError()) != EGL10.EGL_SUCCESS)
|
||||
{
|
||||
OcctJniLogger.postMessage ("EGL Error: " + String.format ("0x%x", anError));
|
||||
}
|
||||
}
|
||||
|
||||
//! Auxiliary method to dump EGL configuration - for debugging purposes
|
||||
@SuppressWarnings("unused")
|
||||
private void printConfig (EGL10 theEgl,
|
||||
EGLDisplay theEglDisplay,
|
||||
EGLConfig theEglConfig)
|
||||
{
|
||||
int[] THE_ATTRIBS =
|
||||
{
|
||||
EGL10.EGL_BUFFER_SIZE, EGL10.EGL_ALPHA_SIZE, EGL10.EGL_BLUE_SIZE, EGL10.EGL_GREEN_SIZE, EGL10.EGL_RED_SIZE, EGL10.EGL_DEPTH_SIZE, EGL10.EGL_STENCIL_SIZE,
|
||||
EGL10.EGL_CONFIG_CAVEAT,
|
||||
EGL10.EGL_CONFIG_ID,
|
||||
EGL10.EGL_LEVEL,
|
||||
EGL10.EGL_MAX_PBUFFER_HEIGHT, EGL10.EGL_MAX_PBUFFER_PIXELS, EGL10.EGL_MAX_PBUFFER_WIDTH,
|
||||
EGL10.EGL_NATIVE_RENDERABLE, EGL10.EGL_NATIVE_VISUAL_ID, EGL10.EGL_NATIVE_VISUAL_TYPE,
|
||||
0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
|
||||
EGL10.EGL_SAMPLES, EGL10.EGL_SAMPLE_BUFFERS,
|
||||
EGL10.EGL_SURFACE_TYPE,
|
||||
EGL10.EGL_TRANSPARENT_TYPE, EGL10.EGL_TRANSPARENT_RED_VALUE, EGL10.EGL_TRANSPARENT_GREEN_VALUE, EGL10.EGL_TRANSPARENT_BLUE_VALUE,
|
||||
0x3039, 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGB, EGL10.EGL_BIND_TO_TEXTURE_RGBA,
|
||||
0x303B, 0x303C, // EGL10.EGL_MIN_SWAP_INTERVAL, EGL10.EGL_MAX_SWAP_INTERVAL
|
||||
EGL10.EGL_LUMINANCE_SIZE, EGL10.EGL_ALPHA_MASK_SIZE,
|
||||
EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RENDERABLE_TYPE,
|
||||
0x3042 // EGL10.EGL_CONFORMANT
|
||||
};
|
||||
String[] THE_NAMES =
|
||||
{
|
||||
"EGL_BUFFER_SIZE", "EGL_ALPHA_SIZE", "EGL_BLUE_SIZE", "EGL_GREEN_SIZE", "EGL_RED_SIZE", "EGL_DEPTH_SIZE", "EGL_STENCIL_SIZE",
|
||||
"EGL_CONFIG_CAVEAT",
|
||||
"EGL_CONFIG_ID",
|
||||
"EGL_LEVEL",
|
||||
"EGL_MAX_PBUFFER_HEIGHT", "EGL_MAX_PBUFFER_PIXELS", "EGL_MAX_PBUFFER_WIDTH",
|
||||
"EGL_NATIVE_RENDERABLE", "EGL_NATIVE_VISUAL_ID", "EGL_NATIVE_VISUAL_TYPE",
|
||||
"EGL_PRESERVED_RESOURCES",
|
||||
"EGL_SAMPLES", "EGL_SAMPLE_BUFFERS",
|
||||
"EGL_SURFACE_TYPE",
|
||||
"EGL_TRANSPARENT_TYPE", "EGL_TRANSPARENT_RED_VALUE", "EGL_TRANSPARENT_GREEN_VALUE", "EGL_TRANSPARENT_BLUE_VALUE",
|
||||
"EGL_BIND_TO_TEXTURE_RGB", "EGL_BIND_TO_TEXTURE_RGBA",
|
||||
"EGL_MIN_SWAP_INTERVAL", "EGL_MAX_SWAP_INTERVAL",
|
||||
"EGL_LUMINANCE_SIZE", "EGL_ALPHA_MASK_SIZE",
|
||||
"EGL_COLOR_BUFFER_TYPE", "EGL_RENDERABLE_TYPE",
|
||||
"EGL_CONFORMANT"
|
||||
};
|
||||
int[] aValue = new int[1];
|
||||
for (int anAttrIter = 0; anAttrIter < THE_ATTRIBS.length; ++anAttrIter)
|
||||
{
|
||||
int anAttr = THE_ATTRIBS[anAttrIter];
|
||||
String aName = THE_NAMES [anAttrIter];
|
||||
if (theEgl.eglGetConfigAttrib (theEglDisplay, theEglConfig, anAttr, aValue))
|
||||
{
|
||||
OcctJniLogger.postMessage (String.format (" %s: %d\n", aName, aValue[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
popEglErrors (theEgl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Interface implementation
|
||||
public EGLConfig chooseConfig (EGL10 theEgl,
|
||||
EGLDisplay theEglDisplay)
|
||||
{
|
||||
int EGL_OPENGL_ES2_BIT = 4;
|
||||
int[] aCfgAttribs =
|
||||
{
|
||||
EGL10.EGL_RED_SIZE, 8,
|
||||
EGL10.EGL_GREEN_SIZE, 8,
|
||||
EGL10.EGL_BLUE_SIZE, 8,
|
||||
EGL10.EGL_ALPHA_SIZE, 0,
|
||||
EGL10.EGL_DEPTH_SIZE, 24,
|
||||
EGL10.EGL_STENCIL_SIZE, 8,
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
|
||||
EGLConfig aConfigs[] = new EGLConfig[1];
|
||||
int[] aNbConfigs = new int[1];
|
||||
if (!theEgl.eglChooseConfig (theEglDisplay, aCfgAttribs, aConfigs, 1, aNbConfigs)
|
||||
|| aConfigs[0] == null)
|
||||
{
|
||||
aCfgAttribs[4 * 2 + 1] = 16; // try config with smaller depth buffer
|
||||
popEglErrors (theEgl);
|
||||
if (!theEgl.eglChooseConfig (theEglDisplay, aCfgAttribs, aConfigs, 1, aNbConfigs)
|
||||
|| aConfigs[0] == null)
|
||||
{
|
||||
OcctJniLogger.postMessage ("Error: eglChooseConfig() has failed!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//printConfig (theEgl, theEglDisplay, aConfigs[0]);
|
||||
return aConfigs[0];
|
||||
}
|
||||
}
|
||||
|
||||
//! Callback to handle touch events
|
||||
@Override public boolean onTouchEvent (MotionEvent theEvent)
|
||||
{
|
||||
int aPointerIndex = theEvent.getActionIndex();
|
||||
int aPointerId = theEvent.getPointerId (aPointerIndex);
|
||||
int aMaskedAction = theEvent.getActionMasked();
|
||||
switch (aMaskedAction)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
{
|
||||
PointF aPntLast = null;
|
||||
if (myActivePointers.size() >= 1)
|
||||
{
|
||||
aPntLast = myActivePointers.get (myActivePointers.keyAt (0));
|
||||
}
|
||||
|
||||
final PointF aPnt = new PointF();
|
||||
aPnt.x = theEvent.getX (aPointerIndex);
|
||||
aPnt.y = theEvent.getY (aPointerIndex);
|
||||
myActivePointers.put (aPointerId, aPnt);
|
||||
|
||||
switch (myActivePointers.size())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
final int aStartX = (int )aPnt.x;
|
||||
final int aStartY = (int )aPnt.y;
|
||||
queueEvent (new Runnable() { public void run() { myRenderer.onStartRotation (aStartX, aStartY); }});
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
myPanFrom.x = (aPntLast.x + aPnt.x) * 0.5f;
|
||||
myPanFrom.y = (aPntLast.y + aPnt.y) * 0.5f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
{
|
||||
for (int aNbPointers = theEvent.getPointerCount(), aPntIter = 0; aPntIter < aNbPointers; ++aPntIter)
|
||||
{
|
||||
PointF aPnt = myActivePointers.get (theEvent.getPointerId (aPntIter));
|
||||
if (aPnt != null)
|
||||
{
|
||||
aPnt.x = theEvent.getX (aPntIter);
|
||||
aPnt.y = theEvent.getY (aPntIter);
|
||||
}
|
||||
}
|
||||
|
||||
switch (myActivePointers.size())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
PointF aPnt = myActivePointers.get (theEvent.getPointerId (0));
|
||||
final int anX = (int )aPnt.x;
|
||||
final int anY = (int )aPnt.y;
|
||||
queueEvent (new Runnable() { public void run() { myRenderer.onRotation (anX, anY); }});
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
PointF aPnt1 = myActivePointers.get (myActivePointers.keyAt (0));
|
||||
PointF aPnt2 = myActivePointers.get (myActivePointers.keyAt (1));
|
||||
PointF aPntAver = new PointF ((aPnt1.x + aPnt2.x) * 0.5f,
|
||||
(aPnt1.y + aPnt2.y) * 0.5f);
|
||||
final int aDX = (int )(aPntAver.x - myPanFrom.x);
|
||||
final int aDY = (int )(myPanFrom.y -aPntAver.y);
|
||||
myPanFrom.x = aPntAver.x;
|
||||
myPanFrom.y = aPntAver.y;
|
||||
queueEvent (new Runnable() { public void run() { myRenderer.onPanning (aDX, aDY); }});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
{
|
||||
myActivePointers.remove (aPointerId);
|
||||
if (myActivePointers.size() == 0)
|
||||
{
|
||||
final int aPressX = (int )theEvent.getX (aPointerIndex);
|
||||
final int aPressY = (int )theEvent.getY (aPointerIndex);
|
||||
double aPressTimeMs = theEvent.getEventTime() - theEvent.getDownTime();
|
||||
if (aPressTimeMs < 100.0)
|
||||
{
|
||||
queueEvent (new Runnable() { public void run() { myRenderer.onClick (aPressX, aPressY); }});
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (myActivePointers.size() == 1)
|
||||
{
|
||||
PointF aPnt = myActivePointers.get (myActivePointers.keyAt (0));
|
||||
final int aStartX = (int )aPnt.x;
|
||||
final int aStartY = (int )aPnt.y;
|
||||
queueEvent (new Runnable() { public void run() { myRenderer.onStartRotation (aStartX, aStartY); }});
|
||||
}
|
||||
//queueEvent (new Runnable() { public void run() { myRenderer.onStopAction(); }});
|
||||
break;
|
||||
}
|
||||
}
|
||||
///invalidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Fit All
|
||||
public void fitAll()
|
||||
{
|
||||
queueEvent (new Runnable() { public void run() { myRenderer.fitAll(); }});
|
||||
}
|
||||
|
||||
//! Move camera
|
||||
public void setProj (final OcctJniRenderer.TypeOfOrientation theProj)
|
||||
{
|
||||
queueEvent (new Runnable() { public void run() { myRenderer.setProj (theProj); }});
|
||||
}
|
||||
|
||||
//! OCCT viewer
|
||||
private OcctJniRenderer myRenderer = null;
|
||||
|
||||
//! Touch events cache
|
||||
private SparseArray<PointF> myActivePointers = new SparseArray<PointF>();
|
||||
|
||||
//! Starting point for panning event
|
||||
private PointF myPanFrom = new PointF (0.0f, 0.0f);
|
||||
|
||||
}
|
Reference in New Issue
Block a user