We implemented the dynamic placement of B-spline curves in the previous chapter of this series. Now add the following graphical user interface (GUI) to this tool:
Adding this interface can help us specify the size of the surface and its layer when placing the surface.
In a native code application, you can add a graphical user interface through MDL resources (.r files) or MFC resources (.rc files). The former is unique to Bentley applications, and the latter is Microsoft's approach. Although MDL resources do not support visual design, it supports user interaction by defining data without writing program code, which is relatively simple. Furthermore, you can integrate the existing dialog entries (known as controls) in MicroStation into your own dialogs, which is another great benefit of MDL resources. In short, MDL resources play an extremely important role in writing native-code programs. Most of Bentley's internal code is written through MDL resources.MFC resources are rarely used (some are written using the latest WinForm WPF). For more information on MDL resources, please refer to "Dialog Box Manager Overview", "Standard dialog items" and "Dialog Hook Functions" in MicroStationApi.chm.In this example, we will focus on the above two dialog entries. In order to implement this interface, we need to make some design considerations: we need to assign an identifier (ID) to each dialog box and dialog item to make it easier to use and reference in resources and code. We also need to specify most dialog items "Access strings" for quick and direct access to the values they reference. In this example, the defined entry ID and access string are shown below:
1. Add the following definition to HelloWorld.h:
#include <Bentley\Bentley.r.h> #define ItemList_BsplineSurface 1 #define TEXTID_BaseArcRadius 1 #define COMBOBOXID_MyLevel 1 #define HOOKITEMID_MyLevelCombo 1 typedef struct helloworldinfo { double baseArcRadius; char levelName[512]; }HelloWorldInfo;
2. Modify the last item in the CT_CREATE definition in HelloWorldCmd.r and add ItemList_BsplineSurface as follows:
{ 4, CT_NONE, INHERIT, NONE, "BsplineSurface", CMDNAME_PlaceBsSurfaceTool, ItemList_BsplineSurface}
3. Add the following to HelloWorld.r:
#include <Mstn\MdlApi\rscdefs.r.h> #include <Mstn\MdlApi\dlogbox.r.h> #include "HelloWorld.h" CmdItemListRsc ItemList_BsplineSurface = {{ {{10*XC, YC/2, 15*XC, 0}, Text, TEXTID_BaseArcRadius, ON, 0, "", ""}, {{10*XC, YC*2, 20*XC, 0}, ComboBox, COMBOBOXID_MyLevel, ON, 0, "", ""}, }}; DItem_TextRsc TEXTID_BaseArcRadius = { NOCMD, LCMD, NOSYNONYM, NOHELP, LHELP, NOHOOK, NOARG, 15, "%w", "%w", "0.0", "", NOMASK, TEXT_NOCONCAT, "Base arc radius:(~B)", "g_helloWorld.baseArcRadius" }; DItem_ComboBoxRsc COMBOBOXID_MyLevel = { NOCMD, LCMD, NOSYNONYM, NOHELP, MHELP, HOOKITEMID_MyLevelCombo, NOARG, 512, "%s", "%s", "", "", NOMASK, 0, 18, 4, 0, 0, COMBOATTR_READONLY | COMBOATTR_FULLWIDTH | COMBOATTR_SORT, "Placement layer:(~L)", "g_helloWorld.levelName", { {0, 512, ALIGN_LEFT, ""}, } };
a. The command CMD_HELLOWORLD_CREATE_BSPLINESURFACE corresponds to ItemList_BsplineSurface, and ItemList_BsplineSurface defines two item lists. When a command is processed and becomes the current command, MicroStation will find the CmdItemListRsc resource associated with the command and display its content in the Tool Settings dialog box;
b. We have defined a text entry resource for the Base Radius. 15 is the maximum number of characters that can be entered in the text entry. "% W" indicates that the value in the text entry will be displayed in work unit format. The tilde in (~ B) indicates that the B character is underlined-this is what we usually call a mnemonic. When the tool setting dialog is focused, press Alt + B to select the text entry. g_helloWorld.baseArcRadius is the access string for this text entry. We can use this variable to get or set the value of this text entry.
c. In the same way, we have defined a combo box entry resource for the "placement layer". The content of a combo box entry often needs to be assigned by code. To this end, a hook entry ID (HOOKITEMID_MyLevelCombo) is defined in the resource file and associated with the entry. In the future, a hook function in the .cpp file should correspond to the hook entry ID. Therefore, when the user operates the item, the hook function in cpp can be called.
4. Create a MicroStation type file HelloWorldTyp.mt as follows:
#include "HelloWorld.h"
publishStructures (helloworldinfo);
Note: Observe that the .h file is included in the .mt file. The .mt file will be generated as a .r file ,and a .r file generates .rsc and merge it into .ma file.
5. Modify the HelloWorld.mke file as follows:
appRscs = $(o)$(appName).rsc $(o)$(appName)cmd.rsc $(o)$(appName)typ.rsc
$(o)$(appName)typ.r : $(baseDir)$(appName)typ.mt
$(o)$(appName)typ.rsc: $(o)$(appName)typ.r
6. Make more changes to HelloWorld.cpp:
#include <Mstn\MdlApi\MdlApi.h> #include <DgnPlatform\DgnPlatformApi.h> #include <DgnView\DgnElementSetTool.h> #include <Mstn\ISessionMgr.h> #include "HelloWorldCmd.h" #include "HelloWorld.h"
HelloWorldInfo g_helloWorld;
bool CreateBsSurface(EditElementHandleR eeh, DPoint3dCP pBasePt) { MSBsplineSurface bsSurface; MSBsplineCurve bsCurves[4]; DPoint3d center[4]; RotMatrix rMatrix[4]; double radius = g_helloWorld.baseArcRadius; .... } .... virtual bool _OnDataButton(DgnButtonEventCR ev) override { EditElementHandle eeh; if (CreateBsSurface(eeh, ev.GetPoint())) { WString wStr(g_helloWorld.levelName); FileLevelCacheR levelCache = ISessionMgr::GetActiveDgnFile()->GetLevelCacheR(); LevelHandle levelHandle = levelCache.GetLevelByName(wStr.GetWCharCP()); ElementPropertiesSetterPtr setter = ElementPropertiesSetter::Create(); setter->SetLevel(levelHandle.GetLevelId()); setter->Apply(eeh); eeh.AddToModel(); } _OnReinitialize(); return true; }
void myLevel_comboHook (DialogItemMessage *dimP) { RawItemHdr *riP = dimP->dialogItemP->rawItemP; dimP->msgUnderstood= TRUE; switch (dimP->messageType) { case DITEM_MESSAGE_CREATE: { ListModelP pListModel = mdlListModel_create(1); DgnFileP pDgnFile = ISessionMgr::GetActiveDgnFile(); for (LevelHandle lh : pDgnFile->GetLevelCacheR()) { WString lvlName; lh.GetDisplayName(lvlName); mdlListModel_insertString (pListModel, lvlName.GetWCharCP(), -1); } mdlDialog_comboBoxSetListModelP(riP, pListModel); break; } case DITEM_MESSAGE_DESTROY: { ListModelP pListModel = mdlDialog_comboBoxGetListModelP (riP); mdlListModel_destroy (pListModel,TRUE); break; } default: dimP->msgUnderstood= FALSE; break; } }
DialogHookInfo uHooks[] = { {HOOKITEMID_MyLevelCombo, (PFDialogHook)myLevel_comboHook }, }; …… …… mdlDialog_hookPublish (sizeof(uHooks)/sizeof(DialogHookInfo), uHooks);
SymbolSet *setP = mdlCExpression_initializeSet (VISIBILITY_DIALOG_BOX, 0, 0); mdlDialog_publishComplexVariable (setP, "helloworldinfo", "g_helloWorld", &g_helloWorld); g_helloWorld.baseArcRadius = 2000; strcpy_s (g_helloWorld.levelName, 512, "Default");
7. Save all files in Visual Studio, go back to the command prompt and type bmake -a to rebuild the project, then switch to MicroStation to test. When you load the HelloWorld app and type HELLOWORLD CREATE BSPLINESURFACE, you will see the first picture shown at the beginning of this chapter. The following figure is an example where three surfaces are placed, each surface is on a different layer and has a different basic arc radius.
Prev:[[Implementing Interactive tools using DgnTools Class]] | Next:[[Launching applications through the customized interface]] |