User interface language to class library compiler6118446Abstract A computer implemented method that allows C++ classes based on any particular class library to be generated from a standard User Interface Language (UIL) file generated by a variety of GUI builders. A programmer can then use these classes in a familiar manner rather than being forced to use the program framework favored by any particular GUI builder. The GUI builder may then be used as a tool to facilitate the creation of classes that are inherently graphical while leaving the programmer free to deal with the inherently non-graphical bulk of the program. Claims What is claimed is: Description BACKGROUND
______________________________________
Form myForm
.vertline.
+-> MenuBar menuBar
.vertline. .vertline.
.vertline. +-> CascadeButton cascadeButton "File"
.vertline. .vertline. .vertline.
.vertline. .vertline. +-> PulldownMenu pulldownMenu
.vertline. .vertline. .vertline.
.vertline. .vertline. +-> PushButton pushButton "New"
.vertline. .vertline. +-> PushButton pushButton1 "Open"
.vertline. .vertline. +-> PushButton pushButton2 "Close"
.vertline. .vertline.
.vertline. +-> CascadeButton cascadeButton1 "Edit"
.vertline. .vertline.
.vertline. +-> PulldownMenu pulldownMenu1
.vertline. .vertline.
.vertline. +-> PushButton pushButton3 "Cut"
.vertline. +-> PushButton pushButton4 "Copy"
.vertline. +-> PushButton pushButton5 "Paste"
.vertline.
+-> RadioBox radioBox
.vertline. .vertline.
.vertline. +-> ToggleButton toggleButton "X"
.vertline. +-> ToggleButton toggleButton1 "Y"
.vertline. +-> ToggleButton toggleButton2 "Z"
.vertline.
+-> PushButton pushButton6 "Do it"
______________________________________
The HUH procedure generates the following .h file (including miscellaneous MDISP boilerplate such as DECLARE.sub.-- CLASS, constructors, and assignment operators not shown here):
______________________________________
#include "DForm.h"
#include "DMenuBar.h"
#include "DPulldownMenu.h"
#include "DPushBtn.h"
#include "DRadioBox.h"
#include "DToggleBtn.h"
class MyForm: public DForm
public:
virtual int create(const char *name,DWidget *parent,
int manage=1);
DMenuBar *menuBar;
DPulldownMenu *cascadeButton;
DPushBtn *pushButton;
DPushBtn *pushButton1;
DPushBtn *pushButton2;
DPulldownMenu *cascadeButton1;
DPushBtn *pushButton3;
DPushBtn *pushButton4;
DPushBtn *pushButton5;
DRadioBox *radioBox;
DToggleBtn *toggleButton;
DToggleBtn *toggleButton1;
DToggleBtn *toggleButton2;
DPushBtn *pushButton6;
};
______________________________________
Indentation is automatically used to show the widget hierarchy. The widget class names match the names used in the MDISP library. The name of the top level widget in the hierarchy is made into a class name by capitalizing the first character. The HUH procedure generates a corresponding .cc file (including MDISP boilerplate such as DEFINE.sub.-- LOCAL.sub.-- CLASS, and bodies of constructor functions not shown here):
______________________________________
#include "myfile.h"
int MyForm:: create(const char *name,DWidget *parent,int manage)
{
if (!DForm:: create(name,parent,0) return 0;
menuBar = new DMenuBar;
if (!menuBar->createMenuBar("menuBar",this,0,0,1)) return 0;
menuBar->x(100);
menuBar->y(100);
. . .
cascadeButton = new DPulldownMenu;
if (!cascadeButton->createMenu("cascadeButton",menuBar))
return 0;
cascadeButton->attachment()->setLabelString("File");
. . .
pushButton = new DPushBtn;
if (!pushButton->createPushButton
("pushButton",cascadeButton->menu(),0,0,1)) return 0;
pushButton->setLabelString("New");
if (manage)
manageChild();
______________________________________
In the first part of the "create" function, the widget hierarchy is built. Then argument values are loaded into widgets. The normal mode for the HUH procedure is to hard code settings for all resources. This means that any changes to the settings by the Builder Xcessory GUI builder 11 requires not only executing the HUH procedure 27, but also recompiling the generated ".cc" files. Alternatively, resource files 17 may be used: huh -rc myfile.uil The ".h", ".cc", and ".rc" files are generated but the ".rc" file contains resource settings of the form: MyForm*cascadeButton.labelString: File MyForm*pushButton.labelString: New . . MyForm*pushButton6.labelSTring: Do it The ".cc" file no longer contains code to set these resources. Instead, the "create" function begins with the following call: loadClassResources(name,parent,"MyForm"); The call to "loadClassResources" causes a resource database to be searched for all lines of code that begin with the class name, in this case, "MyForm". The appropriate actual resource lines with the proper widget hierarchy is generated on the fly for each instance of MyForm. If the program is called "myAppl", a resource file 17 called "MyAppl" is checked. This file may simply include all of the ".rc" files for all of the Builder Xcessory-generated classes used in the application: #include "MyClass.rc" #include "MyOtherClass.rc" . . Some resources cannot be set in a resource file 17. These include the "leftWidget", "rightWidget", "menuHelpWidget", and "pixmap", for example. It may also be desirable to have certain resources hard-coded. A configuration file loaded by the HUH procedure (described below) controls how these situations are handled. When the HUH procedure is run, a new .rc file is generated although it is empty unless the -rc switch is used. New .h and cc files are only generated if they are different. Thus, a "makefile" contain rules for compiling the generated files as follows: .INIT: file1.rc file2.rc . . . %.rc: %.uil huh -rc $<. That is, if the UIL file 12 changes, the .rc file is regenerated. By specifying all the .rc files in an .INIT rule, it is guaranteed that, if any UIL files 12 have changed, they are recompiled with the HUH procedure Then the rest of the "make" proceeds normally, checking the dates on the .h and .cc files which may or may not have been changed by the HUH procedure. The HUH procedure depends on a resource file 17 called "Huh" which it located in either "./Huh", ".about./Huh", or using the environment variable "HUH.sub.-- OPTIONS". This file shows how various Motif names found in UIL files 12 map into the MDISP objects 18. Comments in this file are preceded by "#" and are self-explanatory. Resources in this file allow a programmer to control what MDISP class and associated "create" function is indicated by a Motif class, control what MDISP member function is indicated by a Motif argument name, and control what MDISP enumerator name is indicated by a Motif argument value name. If a Motif argument value has multiple translations depending on the Motif class, this may also be specified. The programmer indicates what Motif arguments apply ".fwdarw.attachment()" or ".fwdarw.menu()" to MDISP objects 18 in order to access the underlying Motif widgets, indicates what MDISP include files must be #included by the generated C++ code in order to accommodate what MDISP classes will be indicated by what Motif classes, indicates which Motif top level widget classes don't have a good translation to MDISP, and indicates where Builder Xcessory generates redundant information. The programmer can indicate what Motif arguments should not be included in the resource file 17, indicate what Motif arguments should be deferred until all children of the associated widget are created, indicate what Motif arguments should be deferred until all children of the associated widget are created and which are set on the children (i.e. attachments), indicate what Motif arguments cannot be set by an MDISP function call, and indicate what Motif arguments should not be applied if they have a null value. The programmer can indicate which classes require the "createMenu" function, indicate the create function to be used when a certain dialog type is specified, indicate where MDISP combines two levels of Motif widgets into a single class, indicate widgets that are unmanaged by default, and indicate which shell managers are called out by specific HUH switches. As specified in the Huh file, some widgets are created with delayed management to make them behave better. The widget is created unmanaged and then managed after argument functions have been called and children have been defined. Some arguments cannot be set after widget creation. Some widgets behave better if the arguments are loaded at creation time rather than afterwards. One way to achieve this is to use resource files 17. Another way is to move the argument function calls to just before the call to the "create" function. This mode may be set with the following switch: -preload If this switch has been set as the default, it may be cleared with the following switch: -aftload. In either case, arguments that require the use of ".fwdarw.attachment" are always loaded after widget creation. When Pixmaps occur in the UIL file 12, appropriate XPM-3 format ".xpm" files are generated to hold the various pixmaps. These files are only updated when the contents change. It may be desirable to protect various sub-widgets of MyForm. The -prot switch inserts "protected:" after the create function and changes the name of the class to MyWidgetBase. In this case, the user should derive MyWidget from MyWidgetBase and then set up whatever member functions are desired to control access to the sub-widgets. It also appends "Base" to the names of the ".cc" and ".h" files. Normally, it is the programmer's responsibility to create the topLevel widget, usually derived from DWindow to contain the complex widget that is generated. The "createDisplay" function is overridden to allocate and create an instance of widgets. DWindow also installs callbacks and inserts code that causes MyWidgett to properly perform its function. For example:
______________________________________
class MyWidgetWindow: public DWindow
public:
MyWidget *myWidget;
MyWidgetWindow()
{
myWidget = new MyWidget;
}
virtual int createDisplay()
{
return myWidget->create("MyWidget",this);
}
};
______________________________________
Alternatively, the HUH procedure 27 can generate this code if the -win or -pop switch is specified, in which case, the above example is generated as follows:
______________________________________
class MyForm: public DWindow // or DPopup
{
public:
virtual int createDisplay();
DForm *myForm
MenuBar *menuBar;
DPulldownMenu *cascadeButton;
DPushBtn *pushButton;
DPushBtn *pushButton1;
DPushBtn *pushButton2;
DPulldownMenu *cascadeButton1;
DPushBtn *pushButton3;
DPushBtn *pushButton4;
DPushBtn *pushButton5;
DRadioBox *radioBox;
DToggleBtn *toggleButton;
DToggleBtn *toggleButton1;
DToggleBtn *toggleButton2;
DPushBtn *pushButton6;
};
______________________________________
The classname (MyForm) is applied to the DWindow rather than to the DForm. Builder Xcessory provides the ability to create and use classes within the context of some other widget hierarchy. It does this by using naming conventions and special directives in the UIL code which are commented out by "!(BX)" or "!(CX)". If the "-bx-" switch is not set, The HUH procedure 27 reads past this kind of comment and interpret the special directives. In Builder Xcessory, a class may be created as an independent widget hierarchy. An icon for the class then appears on a user pallet and may be instanced just as any other widget. If desired, this class may reside in a separate UIL file 12, in which case, The HUH procedure 27 assumes that that a separate UIL file 12 has been compiled and inputs #include's to the .h files generated by that compilation. In "Instance" mode, Builder Xcessory allows a widget hierarchy to begin with an ApplicationShell. This shell should be appropriately named because a class based on DWindow is generated with this name, capitalizing the first character of the name. That is, if the hierarchy is as follows:
______________________________________
ApplicationShell myAppl
.vertline.
+-> Form myForm
.vertline.
+-> MenuBar menuBar
.vertline. .vertline.
.vertline. +-> CascadeButton cascadeButton "File"
. . .
______________________________________
and the C++ class is generated as follows:
______________________________________
class MyAppl: public DWindow
{
public:
virtual int createDisplay();
DForm *myForm;
DMenuBar *menuBar;
DPulldownMenu *cascadeButton;
. . .
______________________________________
Builder Xcessory allows import of classes defined in external UIL files 12. The main UIL file 12 contains directives such as: include file `directory/filename.uil` include file "directory/filename.uil" and if that file contains any "object" definitions, it assumes that a corresponding `directory/filename.h` file exists to define any classes contained in the UIL file 12. The "-I" switch may be used to indicate a directory to search if "filename.uil" does not have an explicit directory and is not found in the current directory: huh -Idirectory1-Idirectory2 . . . One directory may be specified per "-I". Up to 16 "-I" may be specified in any given run. Builder Xcessory uses a naming convention such that objects representing widgets internal to a class have names that are prefixed by the class name. A UIL object which has no direct references and which has a name beginning with an uppercase character (i.e. "Classname") indicates a Builder Xcessory class. Widgets defined internal to that class have its Builder Xcessory name prefixed by "classname.sub.-- " (first character lowercase). If in Builder Xcessory, an instance of some other class occurs inside of this class, the HUH procedure 27 knows this by recognizing control names that begin with a different prefix. For example: object A . . . { controls { . . . a.sub.-- form1; . . . }}; object a.sub.-- form1 . . . { controls { . . . b.sub.-- button1; . . . }}; translates to: class A { . . . B *form1; . . . };, for example. If "receptors" are used by Builder Xcessory to implement inheritance, two different prefixes occur in the controls. If one of the prefixes in the controls matches the prefix on the object or corresponds to a capitalized class name used as the object name, it indicates that the user had instanced another class but added to it. For example: object B . . . { controls { . . . a.sub.-- form; XmName b.sub.-- form; }}; translates to: class B: . . . A { . . . DName *form; }; If a new class is created from an old one nothing is added, and the HUH procedure 27 looks past comments having the form: !(BX) BxNclass. . . ="Classname" to find the actual class names involved. Builder Xcessory allows one widget in a class to be specified as a "receptor". That is, any widgets that are added in the derived class are created as children of the receptor widget. A given resource of a class may be flagged as "Exposed". Anywhere that class is instanced, alternate values may be set for any exposed resources. If an exposed resource is normally set with a function called "resourceName" and the widget is called "myWidget", the following public member function is generated in the header file: int myWidgetResourceName(type arg) { return myWidget.fwdarw.resourceName(arg); } If an exposed resource is normally set with a function called "setResourceName" and the widget is called "myWidget", the following member function is generated in the header file: int setMyWidgetResourceName(type arg) { return myWidget.fwdarw.setResourceName(arg); } When a Dialog Shell is created in Builder Xcessory and it is made a member of one class or widget hierarchy, Builder Xcessory puts the information about the dialog shell in its comments. The HUH procedure 27 reads past the comments to find the connection between a dialog box and its parent widget. Dialog shells may be made to pop up by calling "manageChild" on the widget directly under the dialog shell widget. A top level shell widget occurring in the middle of some other hierarchy is translated to DWindow but is created with the "createTopLevelShell" function to attach it to the hierarchy. The DWindow "show" or "hide" functions are called to make these windows visible or invisible. If it is specified in Builder Xcessory that classes are to be read in, the UIL file 12 contains "include" directives. If those files in turn include other files, Builder Xcessory generates in the comments, although it should have placed it in the UIL code: !(BX) read.sub.-- include file `filename` The HUH procedure reads past the comment and treats it like a regular include. The following switches are available in the HUH procedure 27: -aftload which sets most arguments just after widget creation. This is the default but it may be changed by -preload; -bx causes the given widget names to be used; -Ipath looks for include files in the directory specified by "path"; -pop generates a DPopup shell; -preload sets most arguments before widget creation rather than after; -prot generates protected classes; -rc generate a resource file 17 ("myfile.rc"). This removes the hard-coding of most arguments from the cc file. The .rc file is always generated but it is empty if the -rc switch is not set; and -win generates a DWindow shell. Switches are set to on by default by setting the following environment variable: setenv HUH.sub.-- DEFAULTS -Ipath1 -Ipath2 -rc . . . Improvements to MDISP that support the present invention have been made. The improvements allow parameters to be set before creation of a widget. Arguments are set in DWidgets without having to first perform a "create". If a "create" has not been done, arguments are buffered and then loaded at creation time. If argument lists are supplied by routines such as "createPushButton", for example, these lists are merged with any buffered arguments. This was implemented because some widgets behave better when pre-loaded or when set in a resource file 17. However, the MDISP improvement existing allows preloading by stepping outside of the member function syntax using Motif style "XtArg" lists. One potential problem with "preloading" is that a class might preload arguments that are superseded when the class is instanced. This problem was solved by having the "preload" check for arguments already having been included in the list and discarding duplicates. Thus a user-defined class can be preloaded while achieving the correct behavior. There are some things that cannot be set after creation, including "items" and "itemCount". Preloading now allows these parameter functions to be called. A new string converter is registered with Motif when DAppl or DApplShell creates are performed. This allows compound strings to be represented by an ordinary resource string using the following syntax: ::[#tag][:t][:r]["str"] where: ::=indicates compound string. tag=the font tag :t=separator (if not seen no separator added to segment) :r=right to left (if not seen left to right assumed) "str"=the text of the string. The components for the compound string can be repeated any number of times. There is also a converter for XPM format pixmaps. This has been implemented in DXIcon so the following expression can be used: DXIcon myIcon(xpm-array); and then, for example:
______________________________________
myWidget->backgroundPixmap(myIcon);
XPM format is something like:
/* XPM */
static char *name[] = {
"16 16 2 1",
".c#000",
"X c #ffffffffffff",
"....XXXX....XXXX",
"....XXXX....XXXX",
"....XXXX....XXXX",
"....XXXX....XXXX",
"XXXX....XXXX....",
"XXXX....XXXX....",
"XXXX....XXXX....",
"XXXX....XXXX....",
"....XXXX....XXXX",
"....XXXX....XXXX",
"....XXXX....XXXX",
"....XXXX....XXXX",
"XXXX....XXXX....",
"XXXX....XXXX....",
"XXXX....XXXX....",
"XXXX....XXXX....",
};
______________________________________
where: The first string in the array is: "width height colors characters indicating: width--Number of pixels across the pixmap height--Number of rows in the pixmap colors--Number of color definitions characters--Number of characters per pixel The next <colors> strings indicate color definitions: "x c color" where: x--<characters> representing a color color--A color name such as White --A color value such as #fff The next height strings of length width*characters contain character codes for each pixel in the pixmap. When a DXIcon is referenced for the first time in a "pixmap" argument function, a conversion operator causes a Pixmap to be generated. These conversions are defined in "DConvert". A global symbol "dApplShell" is also defined there and is set by "DAppl" and "DApplShell" to be the display widget. This avoids the need to have a Widget passed as a parameter to the various conversion functions for reference purposes. There was no direct provision in Motif to have resource files 17 that could handle classes. This has been remedied by the following function in "DWidget.h": loadClassResources("name",parent,"cname"); This is called just before a "create" function to indicate that the widget that is created with "name" and <parent> belongs to class "cname". This causes resource file 17 lines of the form: cname.resource: value or cname*item.resource: value to be applied to the complex widget that is created. When creating a complex class called "MyClass", a "MyClass.h" and "MyClass.cc" are usually created. In addition, a "MyClass.rc" may be created to set resources relative to the class as indicated above. If a program is called "myAppl", a resource file 17 called "MyAppl" is checked. This file may include all of the complex class resource files 17 used in the application: #include "MyClass.rc" #include "MyOtherClass.rc" . . The "create" function has been changed from two arguments to three: create("name",parent,managed=1) where the third argument indicates whether the widget is managed (default True). This change will not affect any normal uses of "create" but may affect complex classes which override "create". DLabel has a two argument "setLabelString" (with the second argument having a default). DDate, DDateTime had one argument "setLabelString". All other "set . . . LabelString" functions had one argument. There was also a need to have a "setLabelString" in DWidget to handle several unaccounted-for cases. Since merely moving "setLabelString" to DWidget caused a conflict with the one argument versions in DDate and DDateTime, those were also changed to two argument (with the second defaulted). All other "set . . . LabelString functions were likewise changed to the two argument form. If the second argument is default, the new converter in DConvert is invoked (via "setString" in DWidget) to enable a more sophisticated compound string capability (as described above). A new set of functions has been added to support callbacks to member functions of arbitrary classes. Wherever a function such as "myname" exists to receive a callback such as "XmNmynameCallback", there is now a function called "mynameCb" which may be called as follows: mynameCb(function) which calls a global "function(Dwidget*,XtPointer)" in response to the signal represented by "myname" or: mynameCb(pointer,classname::function) which calls "pointer.fwdarw.function(DWidget*,XtPointer)" in response to the signal represented by "myname". Thus, a software compiler that converts user interface language (UIL) files generated using any general user interface (GUI) builder into application transportable class library objects that may be used in any application framework has been disclosed. It is to be understood that the described embodiments are merely illustrative of some of the many specific embodiments which represent applications of the principles of the present invention. Clearly, numerous and other arrangements can be readily devised by those skilled in the art without departing from the scope of the invention.
|
Same subclass Same class Consider this |
||||||||||
