Previous Next Contents Generated Index Doc Set Home


CHAPTER 8

Structured Code Generation and Reusable Definitions





Introduction

This chapter describes how Sun WorkShop Visual helps you to control the structure of the generated code. Being able to do this is essential for creating reusable widget hierarchies. These reusable hierarchies, known as definitions, appear on the widget palette and can be added to the hierarchy like any other widget. A detailed description of definitions also appears in this chapter.


Structured Code Generation

Sun WorkShop Visual provides controls for structuring your generated code so that it is more flexible and can be reused more easily. Before reading this section, you should review the structure of the default generated code in "Analysis of the Primary Module" on page 236. In particular, note that the default code has a single creation procedure for each Shell in the design. Widgets are declared as local if they have not been named and global if they are named or are Application Shells.

The structured code controls let you:

Designate any widget in the hierarchy to have its own creation function that returns the widget, including its descendants
Designate any widget to have its own creation function that returns a structure containing the widget and its named descendants
Designate any widget to be defined as a C++ class with descendant widgets as members
Designate a widget as a place-holding container that serves only to house a collection of child widgets
Explicitly specify a widget as global, local, or static
Sun WorkShop Visual's controls for structuring code are located on the "Code generation" page of the Core resource panel.


Function Structures

The simplest case of structured code generation is to designate a widget as a function structure. This makes Sun WorkShop Visual generate a separate function that creates that widget and its descendants. This function is called by the creation procedure for the enclosing widget.

To do this, select the "Code generation" page of the Core resource panel and select "Function" from the "Structure" option menu.

FIGURE  8-1 Example: Structure

The hierarchy shown in Figure 8-1 produces the following generated code, slightly simplified for clarity:1

Widget shell = (Widget) NULL;
Widget form = (Widget) NULL;
Widget button_box = (Widget) NULL;
Widget b1 = (Widget) NULL;
/* This is the creation function for the button_box. */

Widget create_button_box (Widget parent)
{
	Widget children[1];      /* Children to manage */
	Arg al[64];                    /* Arg List */
	register int ac = 0;           /* Arg Count */
	Widget button_box = (Widget)NULL;




	button_box = XmCreateRowColumn ( parent, "button_box", 
		al, ac );
	b1 = XmCreatePushButton ( button_box, "b1", al, ac );
	children[ac++] = b1;
	XtManageChildren(children, ac);
/* The button box is created, but not managed, and returned. */

	return button_box;
}
/* The creation function for the Shell calls the button box creation function. */

void create_shell (Widget parent)
{
	Widget children[1];      /* Children to manage */
	Arg al[64];                    /* Arg List */
	register int ac = 0;           /* Arg Count */




	XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
	shell = XmCreateDialogShell ( parent, "shell", al, ac );
	ac = 0;
	XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
	form = XmCreateForm ( shell, "form", al, ac );
	ac = 0;
	button_box = create_button_box ( form );
/* The constraint resources for the button box are set in the parent's creation function. */

	XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); 
	ac++;
	XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); 
	ac++;
	XtSetValues ( button_box,al, ac );
/* The button box is managed at this point. */

	children[ac++] = button_box;
	XtManageChildren(children, ac);
}
This module now has two functions: one (create_shell()) for creating the whole hierarchy and one (create_button_box()) for creating the button box.


Data Structures

The next type of code structuring is the data structure. This is similar to a function structure, in that Sun WorkShop Visual generates a separate creation procedure for the widget and its descendants. When a widget is designated as a data structure, Sun WorkShop Visual also generates a typedef for a structure including that widget and its children. The creation procedure for the widget creates and sets up that type of structure and returns a pointer to it. A deletion function (delete_<widget_name>) is also generated so that the allocated memory can be freed.

To designate a widget as a data structure, select the "Code generation" page from the Core resource panel and select "Data structure" from the "Structure" option menu.

Using the same hierarchy as shown above, but with button_box designated as a data structure, the following code is produced, slightly simplified for clarity:2

/* First the type declarations are generated for the data structure. */

typedef struct button_box_s {
	Widget button_box;
	Widget b1;
} button_box_t, *button_box_p;
Widget shell = (Widget) NULL;
Widget form = (Widget) NULL;
button_box_p button_box = (button_box_p) NULL;
/* The creation procedure returns a pointer to a button_box structure. */

button_box_p create_button_box (Widget parent)
{
	Widget children[1];      /* Children to manage */
	button_box_p button_box = (button_box_p)NULL;
/* Space is allocated for the structure and the fields are filled in. */

	button_box = (button_box_p) XtMalloc ( sizeof ( 
		button_box_t ) );
	button_box->button_box = XmCreateRowColumn ( parent, 
		"button_box", al, ac );
	button_box->b1 = XmCreatePushButton
( button_box->button_box, "b1", al, ac );
	children[ac++] = button_box->b1;
	XtManageChildren(children, ac);
	return button_box;
}
/* A deletion function is supplied to free the allocated memory. */

void delete_button_box ( button_box_p button_box )
{
	if ( ! button_box )
		return;
	XtFree ( ( char * )button_box );
}
/* Again, the Shell creation function calls the button box creation function. */

void create_shell (Widget parent)
{
	Widget children[1]; /* Children to manage */
	Arg al[64]; /* Arg List */
	register int ac = 0; /* Arg Count */
	shell = XmCreateDialogShell ( parent, "shell", al, ac );
	form = XmCreateForm ( shell, "form", al, ac );
	button_box = create_button_box ( form );
	XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); 
	ac++;
	XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); 
	ac++;
/* The button_box widget has to be referenced inside the structure. */

	XtSetValues ( button_box->button_box,al, ac );
	ac = 0;
	children[ac++] = button_box->button_box;
	XtManageChildren(children, ac);
	ac = 0;
}


C++ Classes

The use of C++ classes is very similar to data structures. Sun WorkShop Visual does not wrap each widget in the hierarchy with a C++ class, but instead designates sections of the hierarchy as classes in their own right. Each widget designated as a C++ class has a class defined for it. Its named descendant widgets become members of that class and widget creation and widget destruction methods are supplied. In addition, if the class contains members that are themselves (pointers to) classes, a constructor and destructor method is generated to create and destroy these members. Note that the widgets are not created at the time of the class instance but by an explicit call to the widget creation function. Similarly, destroying the class instance does not destroy the widgets.

To designate a widget as a C++ class, select the "Code generation" page of the Core resource panel and select "C++/Java class" from the "Structure" option menu. Note that if you designate a widget as a C++ class, then generate C, the widget is treated as a data structure.

This section describes C++ classes. For information Java classes in Sun WorkShop Visual, see Chapter 10, "Designing For Java", starting on page 319.

FIGURE  8-2 Example: C++ Class Structures

The C++ code generated from this example is shown below, simplified for clarity:3

Classes are declared for button_box and shell:

class button_box_c: public xd_XmRowColumn_c {
public:
	virtual void create (Widget parent, char *widget_name = 
		NULL);
protected:
	Widget button_box;
	Widget b1;
	Widget b2;
};




typedef button_box_c *button_box_p;
The shell class has constructor and destructor functions because it contains a pointer to class (or data structure) member:

class shell_c: public xd_XmDialog_c {
public:
	virtual void create (Widget parent, char *widget_name = 
		NULL);
	shell_c();
	virtual ~shell_c();
protected:
	Widget shell;
	Widget form;
	Widget text;
	button_box_p button_box;
};




typedef shell_c *shell_p;




shell_p shell = (shell_p) NULL;
The creation function now becomes a method of the class. This method is declared public in the Sun WorkShop Visual base class, which is supplied with the release:

void button_box_c::create (Widget parent, char *widget_name)
{
	Widget children[2];      /* Children to manage */
	Arg al[64];                    /* Arg List */
	register int ac = 0;           /* Arg Count */




	if ( !widget_name )
		widget_name = "button_box";




	button_box = XmCreateRowColumn ( parent, widget_name, 
		al, ac );
_xd_rootwidget is a protected member of the class that stores the widget that is at the root of the sub-hierarchy. This lets the base class operate on the widget:

	_xd_rootwidget = button_box;
	b1 = XmCreatePushButton ( button_box, "b1", al, ac );
	b2 = XmCreatePushButton ( button_box, "b2", al, ac );
	children[ac++] = b1;
	children[ac++] = b2;
	XtManageChildren(children, ac);
	ac = 0;
}
// The Shell's creation method calls that for the button box.

void shell_c::create (Widget parent, char *widget_name)
{
	Widget children[2];      /* Children to manage */
	Arg al[64];                    /* Arg List */
	register int ac = 0;           /* Arg Count */




	if ( !widget_name )
		widget_name = "shell";




	XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
	shell = XmCreateDialogShell ( parent, widget_name, al, 
		ac );
	ac = 0;
	_xd_rootwidget = shell;
	XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
	form = XmCreateForm ( shell, "form", al, ac );
	ac = 0;
	text = XmCreateText ( form, "text", al, ac );
The button box class is instantiated in the constructor method and so at this point only the widgets need to be created:

	button_box->create ( form, "button_box" );




	XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); 
	ac++;
	XtSetArg(al[ac], XmNtopWidget, 
		button_box->xd_rootwidget()); ac++;
	XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); 
	ac++;
	XtSetValues ( text,al, ac );
	ac = 0;




	XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); 
	ac++;
	XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); 
	ac++;
	XtSetValues ( button_box->xd_rootwidget(),al, ac );
	ac = 0;
	children[ac++] = text;
	children[ac++] = button_box->xd_rootwidget();
	XtManageChildren(children, ac);
	ac = 0;
}




shell_c::shell_c()
{
Instantiate the child classes:

	button_box = new button_box_c;
}
shell_c::~shell_c()
{
Free the child classes:

	delete button_box;
}
If a widget is designated a C++ class and C code is generated, the widget is treated as if it were a data structure.

By default, the generated class is derived from one of the supplied Sun WorkShop Visual base classes. You can override this by specifying the base class in the field below the C++ Access option menu. The Sun WorkShop Visual base classes supplied with the release provide minimal support, sufficient for the generated code to execute correctly. You can modify and extend those classes to provide reusable methods that suit your approach to GUI development.

Descendant widgets appear as protected members of the class if they are named, or if they are themselves data structures or C++ classes. It is therefore important to name the C++ class widget itself and any of its descendants that you want to access as class members. You can alter the default access control by selecting the required level (Public, Protected, or Private) from the C++ Access option menu.

Using an unnamed widget for the C++ class widget itself does not cause an immediate error. However, this is not recommended as numbers assigned by Sun WorkShop Visual can change when you edit your hierarchy.


Callback Methods

The X toolkit functions which invoke callback functions expect a callback function in the following form:

void my_callback (Widget, XtPointer, XtPointer)
An ordinary member function is not suitable as a callback function because the C++ compiler passes it an extra first parameter - the this pointer - that lets it find the instance data for the object. If you use an ordinary member function as a callback function, the member function interprets the widget pointer as the instance data pointer and does not work as expected.

Sun WorkShop Visual uses a common technique to work around this. A static member function (which does not expect a this pointer) is declared and used as the callback function:

static void my_callback (Widget, XtPointer client_data, XtPointer 
call_data)
The client data parameter is used to pass in a pointer to the instance. The static member function merely calls an ordinary non-static member function using that instance pointer and passes on the widget and call data parameters. The non-static member function has the following form:

virtual void my_callback (Widget, XtPointer call_data)
Sun WorkShop Visual generates both function declarations, all the code for the static callback function and a stub for the regular member function which is written by you. Note, because this function is declared as virtual, you can override it in a derived class to modify the behavior. For a discussion of this technique, see "Object-Oriented Programming with C++ and OSF/Motif" by Douglas Young.


Editing Callback Methods

When you add a callback method, Sun WorkShop Visual also adds a declaration for the method (if it has not already been declared). Pressing the "Methods" button in the Callbacks dialog shows you a list of the methods declared in the enclosing class of the currently selected widget.

By default, Sun WorkShop Visual declares methods as not pure virtual and with public access. If these attributes are not as you intended, use the Method Declarations dialog to change them. See "Method Declarations" on page 266 for details.


Method Declarations

If you add a callback as a method, for convenience Sun WorkShop Visual adds the declaration of the method in the enclosing class for that widget. You can view, add and remove method declarations by selecting the widget which is the enclosing class and selecting "Method declarations" from the "Widget" menu. The Method Declarations dialog is shown in Figure 8-3.

FIGURE  8-3 Method Declarations Dialog

To find which widget is the enclosing class, use "Structure colors" from the "View" menu, as described in "Structure Colors" on page 47, and select the nearest ancestor of the widget for which you have added a method. Of course, this would be the same widget if it is defined as a C++ class.


Method Access Control

By default, methods added by Sun WorkShop Visual have public access. You can control the access for individual callback methods using the "Access" option menu in the Method Declarations dialog.


Pure Virtual Methods

You can set the "Pure virtual" toggle to declare the non-static member function as pure virtual. For example, if you set this toggle for a callback method OnNew() in a menubar class, Sun WorkShop Visual would declare the method as:

class menubar_c: public xd_XmMenuBar_c {
...
public:
...
	virtual void OnNew( Widget, XtPointer ) = 0;
};
Because the function is pure virtual, you do not have to provide an implementation of menubar_c::OnNew() and menubar_c becomes an abstract class. That is, you cannot create an instance of menubar_c but only use it as a base class for others.

By default, methods added by Sun WorkShop Visual are not pure virtual.


Deleting Callback Methods

When you remove a callback method from a widget you are only removing the use of the method (the call to it). When you add a method callback in Sun WorkShop Visual, a declaration of the method is automatically added for you. If you want to remove this declaration as well you must remove it from the method declarations list of the widget which is the enclosing class. See "Method Declarations" on page 266 for more information on how to do this and for information on the declaration added by Sun WorkShop Visual.


Changing the Structure and Invalidating Methods

When a callback method is added, the method is declared in the enclosing class, as described above. If you change the structure of this widget (the enclosing class) so that it is no longer a class, the method becomes invalid. To help you when this happens, Sun WorkShop Visual displays the Invalidated Methods dialog, shown in Figure 8-4.

This dialog is modal - you can not continue working on your design until it is closed. It is only ever displayed when you change a widget's structure in such a way that method declarations are made invalid.

FIGURE  8-4 Invalidated Methods Dialog

The Widget list on the left shows all the widgets with methods which are invalidated by changing the structure. When you select a widget any invalidated methods are listed on the right. For each selected method, this dialog shows you the class in which it is currently declared and suggests a new class for the declaration of your method. The "Proposed Class" is always the nearest ancestor class. If there is no other suitable class, this dialog serves as a warning that the method will become a function.

Pressing "Declare" changes the declaration of the selected method to the "Proposed Class". Pressing "Declare All" changes each invalidated method to its respective "Proposed Class".


Method Preludes

You can add additional data or function members to a C++ class using the "Code preludes" dialog. Select "Public methods", "Protected methods", or "Private methods" and type your declarations into the text area (or into the code if you are editing in place). C++ code preludes are generated into the class declaration, both in the primary module and in the Externs file.


Creating a Derived Class

To add a function to a class it is often better to write a new class derived from the generated class. The logical gap between the subclass and generated base class can be used to add members and provide implementations for virtual functions.

By default, Sun WorkShop Visual derives the name of a C++ class from the variable name of the root widget and so the class for the widget menubar is menubar_c:

class menubar_c: public xd_XmMenuBar_c {
...
};
When Sun WorkShop Visual generates code to create an instance of the class, it uses the same name:

menubar = new menubar_c;
You can change the default behavior so that Sun WorkShop Visual declares the generated class under one name and creates the instance under another. For example:

menubar = new mymenubar_c;
To make this change, use the "Instantiate as" field on the Code Generation page of the Core resource panel.


Modifying the Base Classes

By default, Sun WorkShop Visual derives a generated class from a base class appropriate to the type of the root widget. For example, a class with a MenuBar at the root of its widget hierarchy is derived from xd_XmMenuBar_c. The name of the base class can be changed in the Core resource panel.

The Sun WorkShop Visual distribution contains a sample implementation of a set of base classes. These can be used as they stand or modified to add extra functionality appropriate to a particular application area.

A Makefile is included to build the sample base classes. Sun WorkShop Visual makes two assumptions about the base classes:

There is a data member _xd_rootwidget of type Widget.

There is an accessor function xd_rootwidget() that returns the value of _xd_rootwidget to be retrieved.

These assumptions, together with a few items of basic class restrictions, are encapsulated in the class xd_base_c:

class xd_base_c
{
public:
	xd_base_c() {_xd_rootwidget=NULL;}
	Widget xd_rootwidget() const {return _xd_rootwidget;}




protected:
	Widget _xd_rootwidget;
private:
	void operator=(xd_base_c&); // No assignment
	xd_base_c(xd_base_c&);      // No default copy
};
Sun WorkShop Visual places no other constraints on the base classes used. In other words, any set of base classes can be used provided that they are derived from xd_base_c (or another base class that satisfies Sun WorkShop Visual's assumptions).

Note that actual parameters for the base class constructor can be supplied with the class name. If parameters are supplied (if the base class string contains a '()', the class is forced to have a constructor and the parameter string is passed to the base class. For example, setting the "Base class" string to mymenubar_c ("Hello World") for the widget menubar will cause Sun WorkShop Visual to generate:

class menubar_c : public mymenubar_c { 
public: 	
	menubar_c(); 	
	...     
};
...
menubar_c::menubar_c () : mymenubar ( "Hello World" )     
{     
}
...
menubar = new menubar_c;


Children Only Place Holders

The Children Only structure option lets you designate one widget (the Children Only widget) as a container structure for another structure. Children Only widgets provide context for their descendants in the hierarchy, but no code is generated for them. Consider the following example:

FIGURE  8-5 Use of Children Only Structure

When you generate code from the design shown in Figure 8-5, Sun WorkShop Visual produces code for the pulldown menu structure only. This feature lets you generate fragments of the design that can be controlled by your application program.


Note - If you specify a widget as "children only", code is only generated for children which are structured or named. Therefore, if all you have underneath a "children only" widget is unstructured and unnamed widgets, then all you will see in the code is Widget declarations.


Structured Code Generation and UIL

When generating UIL for a design that contains structures of some kind, the approach is basically similar to that for C and C++. Independent hierarchies are generated into the UIL file and separate creation functions are generated into the code file. The creation function fetches the appropriate widgets from the UIL hierarchy and fills in the data structure fields as appropriate.


Changing Declaration Scope

Widgets are normally declared locally in the enclosing creation function unless they are structured in some way, or named. In this case they are declared in the enclosing structure if there is one, or as global variables. This default behavior can be modified by setting the storage class of a widget in the Core resource panel. Setting the storage class to Local forces a widget that would otherwise be declared globally or within a structure to be local to the creation function. Setting the storage class to Global forces an unnamed widget or a named element of a structure to be global. Global status is especially useful for widget-type resources and links as discussed in "Unreachable Widgets" on page 272. The Static option is similar to Global but the declaration is static to the module.

There is no way to force an unnamed widget into a data structure. Unnamed children of a data structure widget are created and managed locally to the data structure's creation procedure.


Unreachable Widgets

When you use the structured code generation in conjunction with widget-type resources such as XmNdefaultButton for a BulletinBoard, you could specify designs that reference widgets that are not in scope. These are considered unreachable widgets. Sun WorkShop Visual attempts to detect these cases and warns you at code generation time. Also, if you use unreachable widgets in conjunction with Children Only structures or dynamic run-time creation of hierarchies, unexpected failures may result.

FIGURE  8-6 Hierarchy with Unreachable Widgets

An unreachable widget is illustrated in Figure 8-6. b1 must be available to the Form's creation function so that it can be used as the default button argument. However, since b1 is local to the button_box function, it is not in scope in the Form's creation function. Sun WorkShop Visual detects this situation and displays the following warning at code generation time.

FIGURE  8-7 Unreachable Widget Error

Code is still generated but it may not compile or run as expected. The simplest solution to this is to force the appropriate widget to be global by using the Storage Class option.


Definitions

Once a hierarchy of widgets has been encapsulated as a structure (either a C++ class or a C structure), you can re-use it in other designs by turning it into a definition. A definition is a reusable hierarchy of widgets which is added to the Sun WorkShop Visual widget palette. Selecting a definition from the palette creates an instance of the definition in the design. This instance can be further modified and in turn be made into a definition.


Prerequisites

A widget hierarchy can become a definition provided that:

  1. The root widget has a non-default variable name.
  2. The root widget has been designated as a C++ class or a structure.
  3. The root widget is not part of another definition.
  4. The widget hierarchy does not contain a definition.
  5. The widget hierarchy does not contain any global or static widgets.

Designating a Definition

Designating a definition requires that the design file containing the widget is saved and the widget marked in it as being a definition. To mark the widget as a definition use the Definition toggle in the Widget menu. Creating a definition freezes the widgets within it. Their resource panels are disabled and you cannot add widgets or change widget names. You can edit the widgets that make up a definition only by temporarily removing the definition status. This should be done with caution to avoid conflicts with designs that use the definition. For details, see "Modifying a Definition" on page 278.

To make the definition available for use in other designs Sun WorkShop Visual needs an external reference to it. This is provided by means of a definitions file which is edited using the Edit Definitions dialog.


Definition Shortcut

The "Define" button in the Palette Menu is a quick way of adding a new definition. It designates the currently selected widget as a definition, saves the design and adds the definition to the palette. The header filename for the definition is taken from the type declarations filename in the code generation dialog. No icon is used.


The Definitions file

The definitions file is read by Sun WorkShop Visual to establish the set of definitions which are to appear on the palette. The definitions filename is specified by setting the definitionsFileName resource. The default value is $HOME/.xddefinitionsrc.

If you need to work on multiple projects, each of which uses a different set of definitions, you can change the definitions file by setting the resource. For example:

visu.definitionsFileName:/home/project6/xddefs
The value of this resource can include environment variables:

visu.definitionsFileName:$PROJECT_ROOT/xddefs
To change to the new setting, exit and restart Sun WorkShop Visual.


Editing the Definitions File

To modify the definitions file use the Edit Definitions button in the Palette menu.

This displays the dialog shown in Figure 8-8.

FIGURE  8-8 Adding a Definition to the Palette.

You can use this dialog to add a new definition, delete a definition, or edit an existing definition. To add a definition, you must supply:

Definition - A definition name
Widget name - The variable name of the root widget of the definition
Save file - The name of a saved design file (.xd)
You can also specify:

Icon resource - A resource name which will be used to locate the pixmap file for the definition. See "Specifying the Icon File" on page 707 for further details
Icon file - A file containing a bitmap or xpm pixmap to be used as the palette icon if one is not found using the Icon resource
Include file - The name of the header file that declares the corresponding structure or class. This file is automatically #included in generated code when instances of the definition are used, therefore you will have to make sure that the compiler can locate it. It must be the same name as the externs file generated from the definition
Resource file - The name of the resource file which contains values for the definition. It is included in the generated resource file when instances of the definition are used. It should correspond to the name specified when the resource file was generated for the definition
Family - The family, or group, to which this definition belongs. This is only relevant to the display of definitions on the widget palette. Definitions are grouped together in families. One family is displayed at any given time. You can change which family is displayed by selecting from the option menu above the definitions on the widget palette. By default, definitions are assigned to the "Default" family. You can specify any name for a family. You can also group any number of definitions in the same family
Help information - A document and tag pair which can be used to provide help to users. See "Online Help for Definitions" on page 282 for more details
MFC Offset - This field is only present when Sun WorkShop Visual is in Microsoft Windows mode. In Microsoft Windows applications controls are given a unique number by which they are identified. Sun WorkShop Visual attempts to generate unique numbers and in most circumstances there will not be a problem. However when adding widgets to an instance which has a very large number of controls already, it is possible for the numbers to overlap. The MFC offset is added to the id of a control which is being added to an instance. By increasing this number you can make sure that the control's id does not clash with any of the controls in the definition
Attributes not set at creation time can be set later. For example, you can test and debug a definition before designing its icon.

You can use the "Prime" button to fill in several of the fields for the currently selected widget.


Base Directory

If a definition is specified with a relative file name (a name that does not start with /), Sun WorkShop Visual adds the base directory to the front of the file name. If a base directory is not specified, the directory that contains the definitions design file is used.

To specify a base directory, display the Edit Definitions dialog, click on "Base Directory", select a new directory and click on "Apply". The new base directory is saved in your definitions file and is immediately used in the current session of Sun WorkShop Visual. The base directory cannot be changed if the current design contains instances of existing definitions.


Modifying a Definition

Widgets in the definition are frozen. You cannot add or delete widgets, rename them, set constraints on them in the layout editor, or reset resources. To modify a definition, you must temporarily undefine it. When you need to modify a definition, use the following steps:

  1. Open the save file that contains the definition.
  2. Select the root widget of the definition.
  3. Pull down the Widget Menu and turn off the "Definition" toggle.
Turning off the toggle unfreezes the widgets in the definition so you can make any necessary changes. After making your edits:

  4. Select the root widget and set the "Definition" toggle on again.
  5. Regenerate the code file and externs file.
  6. Save the design.

Impact of Modifying a Definition

Changing a definition affects every design file that uses it. Each time you open a design that uses a definition, Sun WorkShop Visual also opens the file that contains the definition and merges information from the two files. If the definition has been modified, Sun WorkShop Visual tries to reconcile the new definition with the design that uses the old version of it.

If any changes cannot be reconciled, Sun WorkShop Visual displays an error message and saves any irreconcilable parts of the design in temporary Sun WorkShop Visual clipboard files. At this stage there are several ways to proceed:

Paste the clipboard file into your design and manually resolve its contents with the new definition
Discard the clipboard file contents altogether
Exit from Sun WorkShop Visual without saving and modify or revert the definition so that it is compatible with the designs that use it
To minimize the risk of incompatibilities:

Avoid changing the names of widgets in the definition
Replace a widget in the definition only with a subclass widget of the same name. For example, replacing a Label "foo" with a PushButton "foo" is normally safe


Instances

To create an instance of a definition simply click on the appropriate button in the palette. The instance is shown with a colored background.

Definitions and instances must be in separate designs. Although you can see them in the same design within Sun WorkShop Visual, the generated code does not compile unless they are separate.


Definition Families

Definitions are grouped together on the widget palette according to their family. An option menu above the definitions on the widget palette allows you to change which family is currently displayed. See "Editing the Definitions File" on page 275 for details on specifying a definition's family.


Modifying and Extending an Instance

Creating an instance of a definition corresponds to creating an instance of the structure (either a C structure or a C++ class). You can modify an instance after you have created it provided that the modifications can be reflected in the generated code. For example, you can set resources on widgets or add children to widgets only if they are accessible (i.e. if they are named and, for C++, they have an appropriate access mode). You cannot remove widgets or change their names. The root widget is an exception. Because the root widget of the instance is always accessible (through the member function xd_rootwidget()), it can always be modified.


Note - You cannot move a widget in the layout editor, or specify constraints for it, unless it is accessible.

Creating a Derived Structure

It is frequently useful to create a new structure that is derived from the definition. To do this simply set the Structure option on the Code generation page of the Core resources dialog. The derived structure can only be set to the same value as the definition, e.g. it is not possible to derive a C++ class from a C structure.


Overriding a Definition Callback Method

Inherited methods from definitions can be overridden in the instance so that the instance has different behavior from that specified in the definition.


Compiling Code Containing an Instance

To compile code generated from a design containing an instance of a definition, you need to link in the definition code too. There are two ways to do this:

  1. Link in a library containing the definition code
  2. Compile the definition code and the instance code together
These are explained separately below.


Using a Library

To link a library containing the definition code in with the instance code, first compile the code for the definition into a library. Usually, on UNIX and using C or C++, this is done in the following way:

make <definitioncode>.o
ar r <definitionlib>.a <definitioncode>.o
You then need to edit your Makefile for the code containing the instance so that:

  1. The compiler can locate the header file for the definition. Sun WorkShop Visual automatically #includes this header file into the code generated for the instance.
  2. The linker can locate the library containing the definition code. Simply add the full pathname of the library to "EXTRALIBS".

Compiling the Definition with the Instance

Another way of compiling the instance of a definition involves generating the definition, the instance of it and a corresponding Makefile into the same directory. You can tell Sun WorkShop Visual to configure the Makefile so that the definition and instance can both be compiled into the same application. The following instructions show you how to do this.

  1. Open the design containing the instance first.
  2. Make sure you are generating a "Main program"
  3. Set the "New" and "Template" toggles in the Makefile Options dialog.
  4. Generate all the required files.
  5. Open the definition design.
  6. Unset the "Main Program" generate toggle.
  7. Unset the "New" toggle in the Makefile options dialog, leaving the "Template" toggle on.
  8. In the Code Options dialog, set "Links" to None (you have already generated the links functions, doing so twice would result in a linker error).
  9. Generate the code, externs and Makefile (and resources if required).
  10. Type:
make

  at the command prompt.
Doing the above will give you one application containing your instance.


Definitions and Resource Files

Resource values for widgets that are components of definitions can be either hard-coded or specified in resource files.


Instances and Definition Resource Files

When you specify a resource file for a definition, Sun WorkShop Visual #includes that file in the resource file for any design that contains an instance of the definition. The Xlib mechanisms that read the resource file interpret this directive and use it to find the resource file for the definition.


Online Help for Definitions

To record information about a definition and communicate with other developers who are using it, you can provide online help for definitions. The online help is accessed in the Sun WorkShop Visual interface by using the <Tab> and arrow keys to get to the icon or button for the definition, then pressing the <osfHelp> key (usually <F1>).

Help files are stored in subdirectories of the Sun WorkShop Visual help directory. The help directory is determined by the helpDir resource. By default, it is

$VISUROOT/lib/locale/${LANG}/help
where VISUROOT is the path to the Sun WorkShop Visual installation root directory and LANG is the name of your locale (default C).


Text Help Documents

Text help documents are in HTML format. The name of the file is formed by concatenating the document name and marker name. These are joined using the value of the visu.userHelpCatString resource. By default this resource is set to "." The file is then given a ".html" suffix. Sun WorkShop Visual looks for this file in the UserDocs subdirectory of the Sun WorkShop Visual help directory.



1 The comments describing the functions and procedures are not generated.

2 The comments describing the functions and procedures are not generated.

3 The comments describing the functions and procedures are not generated.


Previous Next Contents Generated Index Doc Set Home