The GUI interpreter layer

GUIInterpreterAs described in the previous post, the Mitopia-to-renderer communications path is implemented almost exclusively through the function UI_Command() which consists of a parser for Carmot-E based scripts using custom procedures and $functions registered by the renderer in order to implement the GUI connection.   Because such explicit GUI control is normally relatively ‘low bandwidth’, the benefits to be gained by passing these behaviors through an interpreted GUI language outweigh any possible timing overhead this might imply (which is minimal since GUI commands can be send in bulk as part of a large script).  In particular, the intermediate text form can easily be sent across the network or to another thread thus allowing remote, non-local, and potentially asynchronous interactions with the GUI.  Additionally this arrangement allows dynamic on-the-fly UI translation (i.e., software localization) to be supported.

Another advantage of this approach is that it minimizes the size and complexity of the registration layer with any registered renderers since the overwhelming bulk of GUI behaviors can be accessed through the single registration of the necessary interpreter function invoker by the renderer.  Also, the intermediate text form allows logging of GUI activities and can greatly assist in debugging GUI problems.  Any new universal renderer plugin that wishes to provide its services to Mitopia® should attempt to interpret as much of the simplified plugin language as possible within the procedure and/or $function invoker.  The fact that the language is Carmot-E which is also used within MitoMine™ and other areas of Mitopia® to tie things to the underlying ontological data held in collections, means that that those familiar with one use of the language are able to work in the others, and indeed you can call most MitoMine™ $functions from within GUI scripts.  There are however some minor differences in the Carmot-E runtime for GUI scripts as follows:

  • In the GUI language, there is no equivalent for the $ and # symbols of MitoMine™, though other registers are the same, and the form @$aa is allowed.
  • In the GUI language, the procedure “SetNode(collection,offset)” is used to specify the current data node tied to the GUI (rather than the <@1:4> plugin).  Once designated in this manner, fields of the designated node can be referenced in an identical manner to that provided by MitoMine™.  You may designate a new node at any time.  If you wish to obtain result values from the GUI, you can do so only by specifying a suitable typed collection node using “SetNode“, and then assigning the desired results to this collection element in the GUI script from where they can be examined later.  You may also use this technique to pass complex data sets to the script where once again they can be referenced by field path given the designated node.  You may need to define a suitable type and create a collection containing an element of that type in cases where your code is not using existing types defined in the ontology.  The functions UI_CreateGUIdataPath() and UI_DisposeGUIdataPath() are provided to simplify this process.  The function UI_CommandReply() provides a simple shortcut method for returning basic built-in type results.
  • In the GUI language, there is currently no “if” and “ifelse” statement since these operate by nesting parsers and the GUI parsers are not truly nested in this context (yet!).
  • Unlike MitoMine™ $functions, most GUI language procedures do not return a value.  Procedures can be distinguished from $functions by the lack of a leading ‘$‘ character.  Note that you can utilize many MitoMine™ $functions within GUI language scripts although any $functions that are dependent on a mining context will not work correctly.  Those $functions in MitoMine™ that cannot be called from non-MitoMine™ contexts are marked with an asterisk in the MitoMine™ documention.  Required GUI language $functions must also be registered by the renderers, and these can be used within scripts in an identical manner to MitoMine™ $functions.  Individual renderers can also extend the required $function set to add renderer-specific $functions or override renderer independent GUI $functions provided by the plug-in layer.
  • MitoMine™ scripts can also intermix GUI commands thus allowing them to be used in addition as GUI scripting tools.

For a complete description of the GUI interpreter and the various $functions and procedures it provides as well as details of how to register other renderers with the interpreter, see detailed Mitopia® documentation, or consult the API documentation for UI_Command().  The Listing below gives a number of examples of UI_Command() and related calls taken from actual code:

UI_Command(“ProcessControlList(“Disable”,%llu,%ld,%ld,%ld)”,winp,kStopSrv,kBackup,kRestore);
UI_Command(“LinkStringList(%llu,%ld,%d,”%s”,%d)”,contP->altWndRef,kFixupToolsList,contP->fToolsSL,kStdDelimiter,YES);
UI_Command(“Draw(%llu,%ld)”,contP->altWndRef,kCacheDisplayList);

xh = US_StrToHdl(“”);
UI_CreateGUIdataPath(TM_GetTypeID(NULL,”ET_ListColumnData”),&dpC,&dpO);
US_SprintfCatHdl(xh,”$a = %llu; $b = %ld; $c = %ld; $d = %ld; SetNode($c,$d); “
“dataType = %ld; AddListColumn($a,$b,”Input”,0);”
“AddListColumn($a,$b,”Output”,1);”,
contP->altWndRef,kCacheDisplayList,dpC,dpO,
kAttribute);
for ( max = US_CountColumns(sL,1,0,”t”) – 2, i = 0 ; i < max ; i++ )
{
    US_strcpy(file,scP->algorithms[i].fnName);
    US_SprintfCatHdl(xh,”AddListColumn($a,$b,”%s”,%ld); “,file,2+i);
}
LOCK_HDL(xh);
UI_Command(*xh);
KILL_HDL(xh);
UI_DisposeGUIdataPath(&dpC);

UI_CommandReply(kInt32Type,&m,”fInt32 = $GetValue(%ld,%ld,0)”,contP->altWndRef,kNoRawMapping);

In particular, note the middle example involving the use of a C code loop within Mitopia® to build up an entire interpreted program consisting of many statements which together define the entire content of a list control.  This ability to send long sequences of GUI commands as a single block is critical to performance, particularly when the GUI renderer is actually operating remotely.  Of course the programmer could have accomplished the same thing with just a single ‘link’ command specifying a list held within Mitopia’s ontology.

The Data Model Interface

Unlike the Mitopia-to-renderer (M2R) path, the renderer-to-Mitopia (R2M) communications path is not passed through an interpreter in order to create the necessary abstract interface.  This is because during the process of data discovery by the GUI renderer, it may need to make hundreds or thousands of calls very rapidly in order to explore and display all nodes of a large linked collection for example.  In general it is the case that a vastly larger number of ‘inquiries’ pass from the GUI renderer through Mitopia’s data model abstraction to the underlying data, than do ‘inquiries’ or ‘commands’ passing from Mitopia® to the renderer.  This means that the timing overhead of an interpreted connection can less easily be tolerated in the R2M path.  For this reason Mitopia® provides a very high performance abstract interface to data held in the flat memory-model through the ‘DataModels’ package and API.  Note that the flat memory model abstraction includes all Mitopia® structures, not just those described by the Carmot ontology.  For example, data held in Mitopia’s ‘string list’ abstraction can also be discovered and displayed by renderers using the DataModels layer.  In this regard, the DataModels layer is a high-level generalized abstraction for discovering data types and content on the fly.

One of the forms of data that can be discovered through the DataModels layer is data described by Mitopia’s type manager and held in collections.  One part of the discoverable data described by the type manager is that associated with the Carmot ontology for the system (i.e., I.DEF and others).  From the perspective of the GUI renderer doing the data discovery, the interface to all data accessible through the DataModels layer is identical and it cannot tell directly which lower-level abstraction is actually describing the data.  This extra level of abstraction allows the GUI renderer to be easily connected to a much wider range of data residing within Mitopia® although the bulk of all data accessed and displayed through the DataModels layer is ontological data.

The DataModels package provides a series of API functions starting with “DM_r” which can be called by the GUI renderer to implement every possible data discovery operation that might be required by a GUI renderer.  This includes all operations for exploring hierarchical collections, for discovering types and type fields, for discovering field content, layout restrictions, selections and all other things the renderer might need to know to display and interact with the underlying data.  Many other specialized API functions are provided by the DataModels abstraction to assist in renderer operations.  Since most GUI renderers tend to be implemented in OOP languages, often C++, it is probable that to connect the renderer to Mitopia®, the renderer methods must be sub-classed within an adapter layer which in turn uses the DataModels abstraction to make the connection thereby avoiding the need to fully understand the lower level Mitopia® API layers.

Mitopia® in turn expects the renderer to provide certain ‘behaviors’ in support of the data model abstraction and these are registered by the adapter layer using the Mitopia® API functions RP_DefineDMRendererPlugin(), RP_DefineCMRendererPlugin(), and RP_DefineWMRendererPlugin().  The complete set of defined plugin points (in either direction) can be found in the ‘RendererPlugin.h‘ header file.  Using the definitions in this file it is possible to create and register new renderers with the Mitopia® architecture so that those renderers are able to discover, access, and display data held within Mitopia®.  The full details of how to do this are beyond the scope of this post and are covered by other Mitopia® documentation.  A correctly implemented renderer using this abstraction can allow the user to discover, scroll, and navigate Mitopia® data collections containing millions of nodes in real time.

While the details of the data model interface are beyond the scope of this post, it is important to understand that it is only by the correct connection of a renderer to the DataModels layer, that all of the UI behaviors and auto-generation capabilities described in earlier posts are possible.

On-the-Fly GUI Translation

The Mitopia® architecture provides extensive support for translating text from one language to another.  One of the most important and pervasive aspects of this is the ability to translate the entire GUI for the application from  English to any other supported language on-the-fly.  Because text can appear in so many different places in a renderer, and may be generated by hard code internal to the renderer as well as any number of other sources, it is impractical to define a fixed plugin that is likely to exist in any GUI framework to support this.  Consequently, it is a GUI renderer’s responsibility to ensure that any text that is about to be displayed anywhere in the UI as part of control labeling or contents (if applicable) is passed through some kind of filter function within the renderer which we shall refer to as “PrepareText”.  Furthermore, a means must be provided to allow the renderer adapter layer to utilize Mitopia® translation capabilities, particularly the function XL_GetString() to implement the required “PrepareText” functionality based on the current UI context.

Dynamic software localization - English appearance

The screen shot above illustrates the user in the process of switching the current UI language from English to Arabic while viewing a Country record (in this case Slovakia) in the standard portal.  The screen shot below shows the effect on the GUI of this action.  As you can see most of the control labels in the GUI have been translated by Mitopia® to Arabic, those for which a translation could not be found remain in the original English.  Note also that the renderer itself has flipped the entire UI within the window to reflect the right-to-left nature of the Arabic script.  This flipping even extends to moving scroll bars to the left of list controls.  For most languages which use left-to-right scripts, this flipping does not occur.  You will note that the translation of text strings through the renderer’s “PrepareText” extends to translating the language popup menu which is in fact driven by dynamic discovery off a Mitopia® collection containing a list of the supported languages.  The GUI labels in the rest of the UI are derived automatically from the Carmot type’s field names and thus the ontology for the system is also tied to the translation capability through this behavior.

Dynamic software localization - Arabic appearance

DictionaryWindowMissing translations are entered automatically into Mitopia® translation dictionaries which can be edited through Mitopia’s built-in ‘Dictionaries’ window as illustrated in the screen shot to the right.  Once translated, they immediately impact the GUI display in the language concerned.

The details on how renderers should implement the “PrepareText” functionality are beyond the current scope, however, the main Mitopia® API functions involved are XL_GetString() and XL_FindCollectionDictionary().