Application Composition.


The picture below shows the appearance of the T2lCAD application. It's an application for precise vector drawing. The application was created by assembling suitable components which are arranged in a set of static libraries.

 

 

Here is a somewhat older version of the application and related libraries..

It's quite interesting to demonstrate the assembly of such an application. In the following text is the entire main() function of the application and comments related to this code.

The published main() function has a slightly different form than the current function being analyzed here. However, they correspond fundamentally.

So here are the individual steps of initialization:

➤ Initialization of the TcObjectRegistry object, which will contain all the objects of all documents opened in the application. It's not the case here that each document has its own structure. ( Documents here contains only the file path and ID.) Especially in CAD systems, it's necessary to display drawings on top of each other in various ways. For displaying only one document is then ensured by using an object filter.

int main(int argc, char *argv[]) { TcObjectRegistry::registry();

➤ [1] Here, the registration of commands is performed. These are all the user functions that the user can execute. It's possible to add or remove them as desired. This block is absolutely crucial for the nature and overall functionality of the application.

At the very end, there's a bit of context causing variable behavior for the specific application.

// command registration TcCmds_cmdEngine(); TcCmds_cmdEx::registerCmds_(); Cmds_htmlView::registerCmds_(); CmdsTab_dir::registerCmds_(); CmdsTab_about::registerCmds_(); CmdsTab_cad::registerCmds_(); CmdsTab_cad_toolbar::registerCmds_(); Cmds_cad::registerCmds_(); Cmds_cad_exe::registerCmds_(); Cmds_cadPro::registerCmds_(); CmdsTab_dir::subdirSet("cad");

➤ Next comes the registration of code for object serialization and deserialization.

Serialization and deserialization are implemented as a pair of virtual methods of the respective object. It's not the most ideal part of the code. I've been carrying around a modification in my head for a long time, how to rewrite this part. But there's no time left. For now, it does what it's supposed to do - it serializes and deserializes objects.

The application is able to work only with objects that are registered here. It cannot read others. The loaded objects are then placed into the TcObjectRegistry::registry() initialized above.

// objects registration Point2FCol points(Point2F(0, 0)); points.add(Point2F(0, 0)); StoredFactory::instance().add(new CadObject_linePro ( Point2Col<double>(), nullptr )); StoredFactory::instance().add(new CadLine ( Point2Col<double>(), nullptr )); StoredFactory::instance().add(new CadObject_symbol ( Point2F(), nullptr )); StoredFactory::instance().add(new CadObject_image ( "ble.png", Point2<double>(0, 0), nullptr )); StoredFactory::instance().add(new CadObject_text ( "null", Point2<double>(-100000, 0), nullptr )); StoredFactory::instance().add(new CadObject_dimm ( Point2F(0, 0), -1, nullptr )); StoredFactory::instance().add(new CadObject_refLine ( points, nullptr)); StoredFactory::instance().add(new CadObject_area ( points, Color(Color::BLACK), Color(Color::BLACK), nullptr, false, false)); StoredFactory::instance().add(new CadObject_papper ( Point2F(10e9, 10e9), 50, 1, 200, 200, nullptr));

➤ Commands that we have registered will be sent exactly here - to the Queue. Here we can specify how they will be processed. The Queue will normally execute commands. However, various actions can be performed with it - registering undo, recording it into a script, applying various filters, or whatever you add to the specific implementation.

The object TentativeImplementationCad represents the technique of precise grasping. It is variable - the technique of object grasping can be exchanged for another, or simply experimented with. (The most dreadful feature of current drawing programs is sticking the input point everywhere you don't want it to be.)

// queue instantiation Queue::instance()->set(&CmdQueue::queue()); CmdQueue::queue().setTentaiveImplementation(new TentativeImplementationCad());

➤ Initialization of a component that allows input of commands from another application. In this case, I am using it for experiments with inputting commands via natural language.

Com com; CHAT_SYS.prefixSet("cad_");

A bit of an application context:

QApplication a(argc, argv); a.setApplicationName("T2CAD");

➤ [2] The initialization of the application's frontend is currently taking place. An interesting aspect is the XCALL macro. It involves invoking command not from the UI, but from C++ code.

It's quite possible to visualize it well:

 

EasyViewCad& VIEW = EasyViewCad::instance(); VIEW.createTab("dir2", VIEW.createDir2(), "Directory2"); VIEW.createTab("ofiles2", VIEW.createOfiles2(), "Opened Files"); VIEW.createTab("cad", VIEW.createCad(), "Toolbox"); VIEW.createTab("exed", nullptr, "Executed"); VIEW.createTab("about", nullptr, "Help/About"); #ifdef QT_DEBUG VIEW.createTab("debug", VIEW.createDebug(), "Debug"); #endif XCALL("set_main_tab dir"); EasyViewCad::instance().resize(900,500); EasyViewCad::instance().show();

➤ And now we just keep going until we finish.

return a.exec(); }

Something slipped between the lines. The application draws, which seems to be completely missing in the code above. However, the reality is that the drawing is in the implementation of commands. The block of code [1] will bring along linking to all parts of the program with which the commands interact.

Block [2] must simultaneously comply with the commands registered in [1]. So, all commands processed by the frontend must be registered. It would probably be good to control this situation by software, which I'm not doing yet. Therefore, if a command appears in the frontend that is not currently registered, it simply won't be executed.