## How to create a component for QtEZ

By: Jan Prokop

1.1) First of all, I'll assume you have the QtEZ sources, if so your first task is to:

#include "BaseComp.h"
#include "main.h"

1.2) You will also need to do your includes here for the component this will be replicating, if you are just doing one that will not have another widget that it looks like it may not be necesary.

2.1) Then you will create a class which inherits your base class BaseComponent or some from Qt classes.
All Qt components in qtez are inherited by real Qt inheritance hierarchy with 'z' prefix (zQWidget, zQButton, zQLabel.....)
class
YourClass : public BaseComponent
{
.
.
.
};

or from QButton

class YourClass : public zQButton
{
.
.
};

2.2) Now you need to now declare the kind of component you will be replicating, as a convention I typically call this 'look':

QLabel *look;

2.3.1) Now just the normal constructor, it must accept a QWidget pointer as it's parameter, and it will additionally pass to the base initializer your top name:

YourClass::YourClass(QWidget *parent,
const char *name = "component name",
bool createLook = TRUE) : BaseComponent(parent, name, FALSE)

This will result in a series of your components being called label1, label2, label3, etc. This will be handled by QtEZ.

2.3.2) Instantiate 'look' here, set it to look as you want it to defaultly. I typically leave this to be the Qt default, so if they change what it looks like defaultly I won't have to edit to match. Then finally register your widget with QtEZ:

look = new QLabel(this);
setLook(look);

2.4) You can have a constructor also to delete away strings and stuff you may use later, but make sure you DO NOT DELETE 'LOOK' IN YOUR CONSTRUCTOR! It may be used later by QtEZ upon destruction of your component so leave it there and it will be taken care of by QtEZ.

3.1) Now comes the customization parts, there are several virtual functions that will be called at different points by QtEZ that you can impliment to customize your component.

3.2) Almost every component should fill in the following:

virtual void fillAttributes();
  This will be called when the attributes table requests your attributes you will use this function with the macro ADDATTRIB().

The first argument to ADDATTRIB is the caption (char *).

The second argument is the 'current value'. This value will just need to be used as appropriate (as per the next paragraph):
  It will be a QColor if you user W_COLOR.
  It can be a string or an integer if you use W_TEXT or W_LIST.
  It can be a boolean or integer value if you use W_TRUE.
  It will be a a string if you use W_FILE.

The third argument can be one of:

W_LIST
  Will give the user multiple choice list of options. If you give this you will follow it by the number of items in the list, then follow it by that many _strings_ seperated by columns.
W_FILE
  This will allow the user to select a file, it requires no other parameters.
W_TEXT
  This will allow the user to type in an arbitrary value, it requires no other paramteters.
W_COLOR
  This will allow the user to select/blend a colour.
W_TRUE
  This will allow the user to select a boolean value.

There is a general function you can call, genericFillAttrib(). Almost every component should call this, it will include such basic attributes as width, height, name, etc. It should be a very special case indeed that your component doesn't call this.

virtual void interpretAttributes();
  This function will be called when it comes time to store your attributes into your component. You do this by making a call to the series of functions to the Attribute object, the only argument you must pass is the caption of the attribute you are asking for.

attrib->giveValue(char *caption);
  You can use this for a string value, if you used type W_FILE, W_TEXT, or W_LIST. It will return a QString.
attrib->giveIntValue(char *caption);
  You can use this to ask for an integer value that you put into the table if it's of type W_TEXT, or W_LIST. It will return an int.
attrib->giveBoolValue(char *caption);
  You can use this to get the bool value selected if you put in a W_TRUE. It will return a bool.
attrib->giveColor(char *caption);
  You can use this if you put a color into the Attribute table with W_COLOR. It will return a QColor.

There is a general function you can call, genericInterpAttrib(). If you have it's match, genericFillAttrib() called in the fillAttributes, then you should have this function here to match it.

virtual void fillMembInfo();
  This function is used to fill your component with the base functions it will have. This will normally just be called on creation, though be prepared for it to be called at other times. You should at least put a constructor/destructor pair into the structure. As is the case with inside the QtEZ environment call the constructor function constructor, and destructor destructor. If you intend on giving a base init to the constructor, call that function init, that way the real names will be replaced by QtEZ when the time is right.

To fill the structure you use the function addMember() it's arguments are:

- The function prototype. (char *)
- The base initializer. (char *)
- The source code, this will normally just be "". (char *)
- If the function is virtual, 1 for yes, 0 for no. (int)
- The protection mode as follows: (M_MODE)

- M_PRIVATE, is private
- M_PROTECTED, is protected
- M_PUBLIC, is public
- M_SIGNAL, is signal
- M_PUB_SLOT, is public slot

- Is the function defined here, or externally, 1 for here, 0 for external (int)

There is a general function, genericFillMembInfo(), you can use this as a shortcut to have QtEZ include all the virtual functions provided by QWidget include closeEvent, mouseMoveEvent, mouseClickEvent, etc.

virtual void writeInits();
  This function is called when it comes time to write the class to file. The only thing asked of the component is to write out all the functions necesary to make the widget in the code look like this one, signal connections, function writing etc will be done by QtEZ.

This is done with a pair of functions:

- writeInParent(QString toWrite);
- writeLine(QString toWrite);

Only different between the two is writeInParent() will make this a call to your object as necesary, ie it will prepend 'yourClassInstance->' to toWrite as necesary, if this should never happen then use writeLine(), most should be writeInParent() though. It should also be noted you should put the ending semi-colon and \n onto the the line as you want it to look in the final output, do not worry about putting tabs before your lines though this will be handled by QtEZ.

It is often the case with writing these that the person hasn't changed the attribute in question to cause this line to be written, for example if they don't change the caption from it's default, why should you write out 'setCaption("the new caption");\n'? This being the case there is a facility for you, you will want to check if isWritten("The Attribute Caption in Question") == 1. for example:

        if(isWritten("Caption"))
        {
            i.sprintf("setCaption(\"%s\");\n",look->caption());
            writeInparent(i);
        }

This should allow you to write only the necesary calls, and keep the generated source code to a minimum, again this isn't necesary but it will speed up compilation on your component and in the long run safe you and users of the component time, so it is a Good Thing (tm). There is a macro to help this a little it is:

          i.sprintf("setCaption(\"%s\");\n",look->caption());
          WRITEATTRIB("Caption",i);

This is approximatly the same thing, and will make it a little easier on you, though if you have multiple attributes you depend on, for example width and height, before writing the setGeometry() call, then you will need to use the first construct.

virtual char *queryQType();
  This is used to 'show' what type of component this is, for example if the component you are creating is a QWidget, you will want to return "QWidget" there, that will result in that type being shown in QtEZ environment, it will also be used as the class type if the specialInher() function isn't defined. The main reason for this function is for a consistant look, for example if you are implimenting a component that is either a QMenuBar or a KMenubar depending on what kind of application the user has selected it is recommended you return one string in the queryQType(), something like "Menubar", and then return either QMenubar, or KMenuBar in specialInher() as required, this allows for a more consistant look in QtEZ.

3.3) These functions are more auxiliary then anything. None of them are required by anything, and if left undefined will fall back to default. They are as follows:

virtual int canResize();
  This will say if the widget can be resized after creation by the user.

Return 1 if it can resize.
Return 0 if it cannot.

Default is 1.

virtual int copyable();
  This will say if the widget can be copied, and more importantly pasted back onto the dialog, this will mainly be used if you only want ONE of these components on the dialog.

Return 1 if it is allowed to be copied.
Return 0 if it is not.

Default is 1.

virtual char *specialInher();
  This will override queryQType() as the classtype for your class type, the main purpose is described above in the queryQType() explanation.
virtual int invisableComponent();
  This will determine if the component is invisable, this is so it will show up in QtEZ's dialogs, but will not be visible as a dialog, or a widget, for example a Application component.

Return 1 if the component is to be invisable
Return 0 if it is not.

Default is 0.

virtual int canHaveChildren();
  You can use this to say if your component is allowed to have children.

Return 1 if it can have children.
Return 0 if it cannot.

Default is 1.

virtual int externalLinkage();
  You can use this if upon compilation the component is going to require another library to work, this will mainly be provided by the means of a dynamic component that is not a QWidget, dynamic component creation will follow as an appendix.

Return 1 if it does not require anything extra.
Return 0 if it just needs Qt.

Default is 0.

virtual int instantiate();
  Use this if you do not want your component instantiated, this will also mean that writeInits() will not be called.

Return 1 if it is to be instantiated.
Return 0 if it is not.

Default is 1.

virtual char *specialInit();
  Use this if you do not want the default constructor to be used as '(this,name)' for example the QComboBox I ask to use the '(QWidget *, char *, bool)' constructor.

Return 0 if it is just to use '(this,name)'.
Return a string that will be used during instantiation otherwise.

Default is 0.

virtual QString parseInitSpecial(QString p);
  This function can be a little esoteric, it's basic use is to pase out special variables in the base initializer, for example if you want to pass something that will be user defined (an attribute) to your parent in the baseinit, you can set aside a variable, let's say '$USER_VAR', if the programmer had a basinit that looked like 'init(parent,name,$USER_VAR)' you would be passed that and you would change $USER_VAR to whatever will be appropriate before the actually function call is written to the .cpp file.

Return p if you don't have any variables defined.
Return a string with your variables replace in p if you need to.

Default is to just return p.

virtual char *aboutComp();
  This will allow you to put your name on the 'about' screen of the component if you so choose, you can put the original widget developer's name as well.

Return a string you want to go into the about box if you wish.
Return 0 if you want no about screen.

Default is to have a QtEZ defined about screen.

That should be all there is to creating a component, there will be an appendix at the bottom that will illustrate how to generate a dynamic component, in that it will be included at runtime, rather than in the QtEZ binary. However I would like it if people will send in components created dynamicly to me so I can perhaps make a listing available, and more importantly include in the standard QtEZ distribution if it seems to be a widely used one.

## APPENDIX: DYNAMIC COMPONENTS

On ELF and AOUT systems it is possible to include components dynamically, this is done through a wrapper function, which I suggest wrapping in an extern "C" as:

    extern "C"
    {
         YourClass *yourself(QWidget *parent);
    }

This is the prototype for your function, you will need to replace YourClass with whatever you call the class definition for example 'zDialog'. The implimentation should look like:

    extern "C"
    {
         YourClass *yourself(QWidget *parent)
         {
                return (new YourClass(parent));
         }
    }

I recomend you compile your -fpic and -shared and make sure you link in everything of yours you need, it shouldn't be necesary to link against Qt, or anything in QtEZ. Current convention is to name your shared object with the extention .qtl, the end user will put a configuration of:

Descriptive String;/path/to/yourclass.qtl

If you turn externalLinkage() on in your class, make sure you have a /path/to/yourclass.a that will be an 'ar' of the external classes you had, this will be linked to upon compiling the final program the user makes. You may also put a /path/to/yourclass.img this can be any image that a QImage will read.

This should be all required to make a component dynamic.