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
Status | ||
---|---|---|
|
Status | ||||
---|---|---|---|---|
|
To accomplish a feature like a block library the DWG Expert introduces a simple block container. The block container is a NSMutableArray that stores the block definition name and a corresponding thumbnail. The block container is created and initialized with all blocks from the assets calling -(void)BuildBlockLibrary when CFxARESDelegate triggers onInitializationDone(). The method onInitializationDone() is called only once each application session. The block container uses -(UIImage*)getDrawingThumbnail:(NSString*)drawing from singleton CFxARESInstance to create a block preview.
File: CFxAresDelegate.mm
Code Block |
---|
-(void)onInitializationDone
{
...
[_application BuildBlockLibrary];
} |
File: AppDelegate.m
Code Block |
---|
@interface AppDelegate ()
{
...
NSMutableArray* m_BlockLibrary;
}
-(void)BuildBlockLibrary
{
// Prepare block library.
NSString *bundlePath = [[aresDelegate resourceBundle] bundlePath];
NSString *dwgSamplesPath = [bundlePath stringByAppendingString:@"/Support/Samples/Blocks"];
NSArray *filePaths = [NSBundle pathsForResourcesOfType:@"dwg" inDirectory:dwgSamplesPath];
m_BlockLibrary = [NSMutableArray array];
for ( NSString* drawing in filePaths )
{
BlockDefinition* block = [[BlockDefinition alloc] init];
block._blockFilePath = drawing;
block._blockName = [drawing lastPathComponent];
block._icon = [[CFxARESInstance instance] getDrawingThumbnail:drawing];
[m_BlockLibrary addObject:block];
}
} |
DWG Expert - Insert blocks from external sources
Status | ||
---|---|---|
|
Status | ||||
---|---|---|---|---|
|
The DWG Expert uses another class BlocksDelegate.m to construct a widget that can be used to show all available blocks. The widget is a common OBJ-C class, the NSObject<UITableViewDataSource, UITableViewDelegate>. The block library view processes all data from the block library the block name and the thumbnail. The block delegate is created and initialized in the ViewController.m, the table view is part of the ViewController and shows up accordingly. The final user action will happen on -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath whenever a table cell is tapped. When the table cell is triggered the block insertion is initiated with a command sequenceusing -(void)runCommand:(NSString*)command.
File: ViewController.m
Code Block |
---|
- (void)viewDidLoad
{
...
blockDelegate = [[BlocksDelegate alloc] init];
UINib* blockItem = [UINib nibWithNibName:@"blockview" bundle:nil];
[m_Blocks registerNib:blockItem forCellReuseIdentifier:@"block"];
m_Blocks.dataSource = blockDelegate;
m_Blocks.delegate = blockDelegate;
AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
[blockDelegate SetBlocks:[appDelegate GetBlockDefinitions]];
[m_Blocks reloadData];
...
} |
File: BlocksDelegate.m
Code Block |
---|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
BlockDefinition* blockDef = [m_Blocks objectAtIndex:indexPath.row];
NSString* command = @"_-INSERTBLOCK\n\"";
command = [command stringByAppendingString:blockDef._blockFilePath];
command = [command stringByAppendingString:@"\"\n\\1.0\n1.0\n0.0\n"];
[[CFxARESInstance instance] runCommand:command];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
} |
DWG Expert - Create a custom UI for command prompts
Status | ||
---|---|---|
|
Coming soon.
DWG Expert - Access entity properties
Status | ||
---|---|---|
|
Status | ||||
---|---|---|---|---|
|
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 -(void)mainSelectionSetChanged:(BOOL)isEmpty commonObjectClass:(NSString*)dxfClassName; calls a native method -(NSArray*)GetProperties from CFxNativeConnection to retrieve more information about the entities selected. The DWG Expert uses a simple UIAlertController to display the necessary entity properties. The Obj-C implementation of -(void)DisplayProperties:(NSArray*)properties is part of ViewController.m. DisplayProperties must be executed from the UI thread. A suitable method +(void)runOnUiThread:(dispatch_block_t)block is provided by [CFxARESInstance].
File: ViewController.m
Code Block |
---|
-(void)DisplayProperties:(NSArray*)properties
{
NSString *htmlString = @"<html><head><style> \
table { \
font-size: 1.3em; \
width: 100%; \
} \
</style> \
</head><body><table>";
for (NSString* prop in properties) {
NSString* key = [[prop componentsSeparatedByString:@","] objectAtIndex:0];
NSString* value = [[prop componentsSeparatedByString:@","] objectAtIndex:1];
NSString* row = [NSString stringWithFormat:@"<tr><td>%@</td><td>%@</td></tr>", key, value];
htmlString = [htmlString stringByAppendingString:row];
}
htmlString = [htmlString stringByAppendingString:@"</table></body></html>"];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
message:nil
preferredStyle:UIAlertControllerStyleAlert];
NSAttributedString *attributedStr = [[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding]
options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)}
documentAttributes:nil error:nil];
NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:@"Entity properties" attributes:@{NSFontAttributeName : [UIFont boldSystemFontOfSize:17], NSForegroundColorAttributeName :[UIColor blackColor]}];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
// OK button tappped.
[self dismissViewControllerAnimated:YES completion:^{ }];
[[CFxARESInstance instance] emulateEscKeyPressed];
}];
[alert setValue:attributedStr forKey: @"attributedMessage"];
[alert setValue:attributedTitle forKey:@"attributedTitle"];
[alert addAction:defaultAction];
UIView *firstSubview = alert.view.subviews.firstObject;
UIView *alertContentView = firstSubview.subviews.firstObject;
UIView *firstView = alertContentView.subviews.firstObject;
firstView.backgroundColor = [UIColor whiteColor];
[self presentViewController:alert animated:true completion:nil];
} |
File: CFxAresDelegate.m
Code Block |
---|
-(void)mainSelectionSetChanged:(BOOL)isEmpty commonObjectClass:(NSString*)dxfClassName
{
// User selected enitities, lets show/hide UI for working with selection.
NSArray* properties = [[CFxNativeConnection GetNativeConnection] GetProperties];
if (properties != nil && properties.count > 0)
{
[CFxARESInstance runOnUiThread:^
{
[[self getMainView] DisplayProperties:properties];
}];
}
} |
File: CFxNativeConnection.mm
Code Block |
---|
std::vector< std::pair<OdString, OdString>> GetEntityProperties( OdDbEntityPtr pEntity )
{
std::vector< std::pair<OdString, OdString>> properties;
OdCmColor cmColor = pEntity->color();
properties.push_back( std::make_pair( L"Color", cmColor.colorNameForDisplay() ));
OdDbObjectId idLayer = pEntity->layerId();
OdDbLayerTableRecordPtr pLayer = idLayer.openObject();
properties.push_back( std::make_pair( L"Layer", pLayer->getName() ));
OdDbObjectId idLinetype = pEntity->linetypeId();
OdDbLinetypeTableRecordPtr pLinetype = idLinetype.openObject();
properties.push_back( std::make_pair( L"Linetype", pLinetype->getName() ));
double linetypeScale = pEntity->linetypeScale();
CFxDatabasePtr pDB = pEntity->database();
CFxString sLinetypeScale;
if ( pDB->GetUnitsFormatter()->RealToString( sLinetypeScale, linetypeScale ) == RTNORM )
properties.push_back( std::make_pair( L"LinetypeScale", sLinetypeScale.wide_strU() ));
OdString sLineWeight;
OdDb::LineWeight entityLineweight = pEntity->lineWeight();
if( entityLineweight == OdDb::kLnWtByLayer )
sLineWeight = L"ByLayer";
else if( entityLineweight == OdDb::kLnWtByBlock )
sLineWeight = "ByBlock";
else if( entityLineweight == OdDb::kLnWtByLwDefault )
sLineWeight = L"Default";
else
{
int value = static_cast<int>( entityLineweight );
double newValue;
newValue = value / 100.0;
sLineWeight.format( L"%2f mm", newValue );
}
properties.push_back( std::make_pair( L"Lineweight", sLineWeight ) );
// Read Block Properties
if( pEntity->isKindOf( OdDbBlockReference::desc() ) )
{
OdDbBlockReferencePtr pBlock = OdDbBlockReference::cast( pEntity );
OdGePoint3d pt = pBlock->position();
double dAngle = pBlock->rotation();
OdGeScale3d scale = pBlock->scaleFactors();
OdDbBlockTableRecordPtr pRecord = pBlock->blockTableRecord().openObject( OdDb::kForRead );
OdString strBlockName;
if( !pRecord.isNull() )
strBlockName = pRecord->getName();
properties.push_back( std::make_pair( L"Position X" , OdString().format(L"%f",pt.x ) ) );
properties.push_back( std::make_pair( L"Position Y" , OdString().format(L"%f",pt.y ) ) );
properties.push_back( std::make_pair( L"Position Z" , OdString().format(L"%f",pt.z ) ) );
properties.push_back( std::make_pair( L"Scale X" , OdString().format(L"%f",scale.sx ) ) );
properties.push_back( std::make_pair( L"Scale Y" , OdString().format(L"%f",scale.sy ) ) );
properties.push_back( std::make_pair( L"Scale Z" , OdString().format(L"%f",scale.sz ) ) );
properties.push_back( std::make_pair( L"Rotation" , OdString().format(L"%f", dAngle ) ) );
properties.push_back( std::make_pair( L"Name" , strBlockName ) );
}
return properties;
} |