The DWG Expert addresses the possibilities to customize the core features especially in the ways to introduce more powerful tools to the UI part of the application.
Features
List blocks from external sources
Insert blocks from external sources
Create a custom UI for command prompts
Access entity properties
DWG Expert - List blocks from external sources JAVA C++
To accomplish a feature like a block library the DWG Expert introduces two separate classes. A class to describe the block Block.java (storing the block definition name and a corresponding thumbnail) and a class to manage all existing blocks BlockLibrary.java . The block library is created and initialized with all blocks from the assets using the method BuildBlockLibrary() when CFxARESDelegate triggers onInitializationDone(). The method onInitializationDone() is called only once each application session. The block library uses getDrawingThumbnail() from singleton CFxARESInstance.instance() to create a block preview.
File: BlockLibrary.java
void AddFile( String drawing ) { Bitmap preview = CFxARESInstance.instance().getDrawingThumbnail( drawing ); Block blockDef = new Block(); String blockName = ""; String[] components = drawing.split( "/" ); if ( components.length > 0 ) { blockName = components[ components.length - 1 ]; String[] nameComponents = blockName.split( "\\p{Punct}" ); if ( nameComponents.length > 0 ) blockName = nameComponents[ 0 ]; } blockDef.m_Preview = preview; blockDef.m_Drawing = drawing; blockDef.m_BlockName = blockName; blockDef.m_Id = 0; m_Blocks.add( blockDef ); }
File: ARESDelegate.java
@Override public void onInitializationDone() { ... BuildBlockLibrary(); ... } private void BuildBlockLibrary() { m_BlockLibrary = new BlockLibrary(); AssetManager assets = m_Host.getAssets(); try { final String[] sampleDrawings = assets.list( "Blocks" ); for ( String drawing : sampleDrawings ) { String drawingPath = "assets:/Blocks/" + drawing; m_BlockLibrary.AddFile( drawingPath ); } } catch (IOException e) { e.printStackTrace(); } }
DWG Expert - Insert blocks from external sources JAVA C++
The DWG Expert uses another class BlockLibraryView.java to construct a widget that can be used to show all available blocks. The widget is a common Java class, the RecyclerView. The block library view processes all data from the block library BlockLibrary.java the block name and the thumbnail. The final user action will happen on setOnClickListener() that is connected with a custom handler in setOnDoInsertHandler(). When the handler is triggered the block insertion is initiated with a command sequence using runCommand().
BlockLibraryView.java
@Override public void onBindViewHolder( ViewHolder viewHolder, final int position ) { final Block desc = localDataSet.get( position ); viewHolder.m_Name.setText( desc.m_BlockName ); viewHolder.m_Preview.setImageBitmap( desc.m_Preview ); viewHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if ( m_Handler != null ) m_Handler.doInsert( desc.m_Drawing, desc.m_BlockName ); } }); }
MainActivity.java
public void DocumentCreated() { ... BlockLibraryView.BlockAdapter adapter = new BlockLibraryView.BlockAdapter( m_ARES.GetBlockLibrary().m_Blocks ); m_BlockPanel.setAdapter( adapter ); adapter.setOnDoInsertHandler(new BlockLibraryView.BlockAdapter.OnDoInsert() { @Override public void doInsert(String drawingPath, String blockName) { String command = "_-INSERTBLOCK\n\"" + drawingPath + "\"\n\\1.0\n1.0\n0.0\n"; CFxARESInstance.instance().runCommand( command ); } }); }
DWG Expert - Create a custom UI for command prompts JAVA
Commands that are shipped by default also show up the default user input mask that may not suit well into the host applications surface. The CFxARESInstance allows to disable the predefined controls using the method switchStandardUserInput(). Once this is done it is necessary to create a custom input that cooperates with commands. Whenever a command requires an user action the custom input should request for corresponding values. This can be accomplished with the CFxUserInputDelegate. The CFxUserInputDelegate informs the host application when an user interaction starts interactionStarted() or ends interactionEnded(). The DWG Expert controls a class UserInput.java that takes over the job of the delegate and the user interface. The class must be instantiated and registered as main CFxUserInputDelegate. Depending on the started interaction type the custom user input has to accept the command value or exit the command procedure. The DWG Expert relies on point input and demonstrates the use of acceptWithCoordinates() and cancel().
The method interactionStarted( final String prompt, String[] keywords, int inputType ) basically provides the following kind of data:
Type | Description |
---|---|
prompt | The current command prompt that can be displayed |
keywords | The current command keywords that can be displayed or executed with CFxARESInstance.instance().userInput().acceptWithStringResult() |
inputType | The type of the current command prompt. The active type should be addressed accordingly in the custom user interface. Some types like GetPoint or GetDistance do not require user input fields when the host application only wants to allow picking a point or specifying a distance on the graphics area. Types likes GetKeyword or GetString can not be processed on the graphics area and require corresponding and suitable input fields. |
The command prompt input types are:
public static final int GetPoint = 1; public static final int GetAngle = 2; public static final int GetDistance = 3; public static final int GetOrient = 4; public static final int GetCorner = 5; public static final int GetScale = 6; public static final int GetKeyword = 7; public static final int GetColor = 8; public static final int GetInt = 9; public static final int GetDouble = 10; public static final int GetString = 11; public static final int GetSelection = 12;
Note: It is highly important to always provide to the user a control that allows him to cancel the current command routine. The current command routine can be canceled using method cancel(). The final call will look like: CFxARESInstance.instance().userInput().cancel()
Some command prompts have default values. These default values can be processed with the method accept(). The final call will look like: CFxARESInstance.instance().userInput().accept()
MainActivity.java
protected void onCreate(Bundle savedInstanceState) { ... LinearLayout inputUI = findViewById( R.id.id_userinput ); m_UserInput = new UserInput( inputUI ); } public void OnApplicationStarted() { ... CFxARESInstance.instance().userInput().delegate = m_UserInput; } CFxARESInstance.instance().switchStandardUserInput( false );
UserInput.java
public UserInput( LinearLayout view ) { ... m_Ok.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ... CFxARESInstance.instance().userInput().acceptWithCoordinates( x, y, z ); } }); m_Cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { CFxARESInstance.instance().userInput().cancel(); } }); }
UserInput.java
@Override public void interactionStarted(final String prompt, String[] keywords , int inputType ){...} @Override public void interactionEnded(){...}
DWG Expert - Access entity properties JAVA C++
It may be necessary to run certain actions whenever an entity is selected. The CFxARESInstanceDelegate provides a method that informs the host application a selection has changed. The method mainSelectionSetChanged() calls a native method GetProperties() to retrieve more information about the entities selected. The DWG Expert uses a simple AlertDialog to display the necessary entity properties. The C++ implementation of GetProperties() is stored in Properties.cpp and compiled with the module JNI. Once libJNI.so is loaded , all methods are linked and available to be called.
Properties.java
public static native ArrayMap<String, String> GetProperties();
Properties.cpp
JNIEXPORT jobject JNICALL Java_com_graebert_userinput_Properties_GetProperties( JNIEnv * env, jclass clazz ) { CFxDocument* pDocument = ACTIVE_DOCUMENT(); if ( pDocument == nullptr ) return nullptr; CFxSelectionSet* pSelection = pDocument->GetFxMainSelectionSet(); if ( pSelection->GetLength() != 1 ) return nullptr; OdDbObjectId idSelected = pSelection->GetId( 0 ); OdDbEntityPtr pSelectedEntity = idSelected.openObject(); if ( pSelectedEntity.isNull() ) return nullptr; auto properties = GetEntityProperties( pSelectedEntity ); CFxObjectConstructor arrayCreator( "android/util/ArrayMap" ); arrayCreator.Call(); jobject arrayHandle = arrayCreator.GetResult(); CFxObjectInvocation insertInvocation( "android/util/ArrayMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" ); for ( auto& property : properties ) { CFxJavaString key( property.first ); CFxJavaString value( property.second ); insertInvocation.Call( arrayHandle, key.GetJString(), value.GetJString() ); } return GET_JAVA()->NewGlobalRef( arrayHandle ); }
ARESDelegate.java
@Override public void mainSelectionSetChanged(boolean isEmpty, String commonObjectDxfClassName) { final ArrayMap<String, String> res = Properties.GetProperties(); if ( res != null && res.size() > 0 ) { CFxARESInstance.instance().runOnUiThread(new Runnable() { @Override public void run() { m_Host.DisplayProperties( res ); } }); } }
MainAcitivity.java
Properties.Adapter m_Adapter = null; public void DisplayProperties( ArrayMap<String, String> properties ) { AlertDialog.Builder builder = new AlertDialog.Builder( this ); builder.setTitle( "Entity properties" ); RecyclerView grid = new RecyclerView( this ); m_Adapter = new Properties.Adapter( properties ); grid.setAdapter( m_Adapter ); grid.setLayoutManager( new LinearLayoutManager( this ) ); AlertDialog dialog = builder.create(); dialog.setView( grid ); dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { CFxARESInstance.instance().emulateEscKeyPressed(); } }); dialog.show(); }