How To Program Components In Gambas
Introduction
All the information below is for Gambas 3.
Gambas components are shared libraries written in C, C++ or directly in gambas that add new classes to the gambas interpreter.
A component written in gambas is a normal gambas project with the following distinctive features:
-
In the "General" tab of the project property dialog, the "project type" combo-box is set to "Component".
-
Then a new tab named "Information" is available.
It must be filled with the following details:
-
The progress of the component (i.e. if it is stable or not).
-
The required features.
-
The required components.
-
The excluded components.
-
Some of the project classes are exported.
-
The exported classes that are controls must declare some special public constants that will tell the IDE all the information needed to manage the control.
Many gambas official components are already written in gambas, and you can use them as examples.
The source code of these components is located in the
/comp/src
directory of the gambas source archive.
Here is the list of these components:
Note that some components written in C/C++ have a part written in gambas too:
The source code of the gambas part is located inside the source directory of these components. For example, the gambas part of
gb.qt4 is located in
/gb.qt4/src
.
Exported classes
So the goal of a component is to provide new classes to the Gambas interpreter.
The classes you want to provide must be
exported from your project, otherwise the user of your component won't see them.
To mark a class as
exported, you just have to add the gambas keyword
EXPORT to the beginning of the class file source code.
If a method or a property of an exported class returns an object of another class declared in your component, then this other class should be exported too.
Otherwise, the user won't be able to store a reference on it, unless he uses the
Object datatype.
If an exported class inherits another class declared in your component, then this other class must be exported too.
Otherwise, you will get an error when the interpreter will load the component.
For a good example of a simple component with only exported classes, look at the source code of
gb.settings and its
Settings class.
Hidden exported classes
If you have to export some classes that you don't want the user to see them, you can hide them by just starting their name with an underscore character.
For example, look in the
gb.desktop source code to see many exported classes that are not to be seen explicitely.
With that, you can replace the concept of "virtual classes" that exist only in components written in C/C++.
Controls
Controls are special exported classes that will appear in the IDE control toolbox.
Controls are usually graphical controls that display something and interact with the user.
But they can be normal classes too, and display nothing, like the
Timer control. In that case, they are called
virtual controls.
The GUI components (
gb.qt4 or
gb.gtk) provide two classes that you should use as parent classes for creating your own controls:
UserControl and UserContainer are actually children classes of the
Container class. This way, you can create new controls or new containers by
mixing already existing controls or containers.
For a good example of the use of UserControl, look at the source code of the
FileView control.
This control embeds one
TreeView and one
IconView inside a UserControl, displaying one of them according to the kind of view requested by the user.
For a good example of the use of UserContainer, look at the source code of the
ListContainer control.
This control is a container that allows to create a
ListBox whose items are other controls.
Controls need to declare some special hidden constants that are used by the IDE to manage the control:
Constant
|
Type
|
Default
|
Description
|
_IsControl
|
Boolean
|
FALSE
|
This property must be set to TRUE, so that an exported class becomes a control.
|
_IsContainer
|
Boolean
|
FALSE
|
If a control is a container, i.e. if you can put other controls inside in the IDE form editor.
|
_IsMultiContainer
|
Boolean
|
FALSE
|
If a control is a multiple container, like a TabStrip.
|
_IsVirtual
|
Boolean
|
FALSE
|
If a control is virtual, i.e. just a normal class that you can put in the form editor, like the Timer or Printer class.
|
_IsForm
|
Boolean
|
FALSE
|
If a control is actually a form, i.e. the top-level container of all controls of the same family.
|
_Family
|
String
|
"*"
|
The family of the control, i.e. the kind of top-level object where you will be able to put the control.
For example: "Form" for a form control, "Report" for a control report, and "*" for a control that can be put anywhere.
|
_Group
|
String
|
_Family
|
The IDE toolbox tab name where the control will be put. By default, the family name will be used, or the "Special" group if the control has no family.
|
_Similar
|
String
|
""
|
A comma separated list of similarity groups. The IDE form editor will allow the control to be replaced by any other control sharing the same similarity groups.
A similarity group is normally a control name.
|
_Properties
|
String
|
""
|
The list of control properties. See below.
|
_DefaultEvent
|
String
|
""
|
The control default event. See below.
|
_DefaultSize
|
String
|
""
|
The control default size. See below.
|
_DefaultArrangement
|
String
|
""
|
The automatic arrangement if the control is a container and if it arranges its children automatically.
See below.
|
_DrawWith
|
String
|
""
|
The real GUI control used for drawing the control inside the form editor. See below
|
Only the
_IsControl
and the
_Properties
constants are mandatory.
These hidden constants are inherited like any other constant. So you don't have to actually
declare them in each control, as soon as there is some inheritance relationships between them.
The _Properties Constant
This constant is the most important, and is mandatory. It describes all properties that will appear in the IDE property sheet for the control,
their type, their default value, and other information depending on the property type.
Syntax
This special constant is a string having the following form:
PUBLIC CONST _Properties AS String = " [ * , ] Property1 , Property2 , ... "
Each property has the following syntax:
[ - ] Name [ { Kind [ Arguments ] } ] = Default
-
Name is the name of the property. Of course, the property must be declared and implemented in the control source code.
-
Kind is the kind of the property. It can be more accurate than the property datatype. For example, "Color" will mean that the property is an integer, but the IDE property sheet will open a color chooser to define its value. If not defined, the kind of the property is its datatype.
-
Arguments are optional arguments that depends on the value of Kind.
-
Default is the default value of the property. The syntax here depends on the property kind.
The first property can be a star, meaning that the control automatically gets all properties declared in the
_Properties
constant of its parent class.
In that case, a property name can start with a minus sign. It means that this property must be removed from the list inherited from the parent class.
Property kinds
Here are the different values of
Kind that are supported at the moment:
Property kind
|
Description
|
Arguments
|
Color
|
An integer that represents a color.
The IDE will pop up a color chooser to edit the value of this property.
|
|
Font
|
A font.
The IDE will pop up a font chooser to edit the value of this property.
|
Font [ :Fixed ]
Use Font:Fixed to allow fixed fonts only.
|
Path
|
A file path.
The IDE will pop up a file chooser to edit the value of this property.
|
|
Picture
|
A picture located in the project directory, or a stock icon.
The IDE will pop up a picture chooser to edit the value of this property.
|
|
Range
|
An integer value with a minimum and a maximum.
The IDE will use a SpinBox control to edit the value of this property.
|
Range:Minimum;Maximum
|
The
Default value must follow the datatype of the property. For boolean properties, you can specify "True" or "False" as default value.
You must be careful when defining (or not) the
Default value of a property.
-
First, if not specified, the taken default value is the default value associated with the property data type (FALSE for a Boolean property, 0 for a numerical one...).
-
Last, the default value must be accurate with the property implementation. Because when a property is set to its default value in the IDE form editor, no code is emitted to initialize the property at run time.
Constant lists
For properties that take their value into a list of predefined constants of the same class,
you can specify a class instead of a property kind, with an optional list of constants.
Here is the syntax:
Property kind
|
Description
|
Arguments
|
Class name
|
A list of constants.
The IDE will will use a ComboBox control to edit the value of the property, and will fill it with the specified constants.
|
Class . ( * | Constant1 ; Constant2 ; ... ) [ = Default ]
If a star is used instead of a constant list, then all public constants of the specified class will be used.
|
If specified, the value of Default must be the name of one of the constants. Not its real value!
Examples
For example, the value of
Control._Properties
is:
X{Position},Y{Position},Width{Dimension},Height{Dimension},Visible=True,Enabled=True,Font{Font},
Background{Color}=-1,Foreground{Color}=-1,Tag,
Mouse{Mouse.Default;Blank;Arrow;Cross;Wait;Text;SizeAll;SizeH;SizeV;SizeN;SizeS;SizeW;SizeE;SizeNWSE;SizeNESW;SplitH;SplitV;Pointing}=Default,
ToolTip,Drop,Expand,Ignore
It is inherited by all other controls and containers.
Here is the value of
ListBox._Properties
:
*,List,Mode{Select.*}=Single,Sorted
The Other Special Constants
The _DefaultEvent constant
This constant is a string that represents the default event of the control. This default event is used when you click twice
on a control in the IDE form editor.
For example:
PUBLIC CONST _DefaultEvent AS String = "Click"
This constant is optional, but you should declare it anyway.
The _DefaultSize constant
This constant is a string that represents the default size of the control when it is dropped from the toolbox on the form editor.
It is the width and height as multiple of
Desktop.Scale, separated by commas.
For example:
PUBLIC CONST _DefaultSize AS String = "36,36"
This constant is optional. If not declared, the IDE will try to do its best.
The _DrawWith constant
This constant is a string that tells the IDE which control should be used for drawing it on the form editor.
By default, controls that are members of
gb.qt5,
gb.form and
gb.form.mdi components are drawn by being instanciated with the Design property set.
If a control is not a member of the components above, then the IDE will draw a frame with the control icon and the control name inside.
By defining this constant, the IDE will not use a
DrawingArea, but the control you specified.
For example:
PUBLIC CONST _DrawWith AS String = "TextBox"
The _DefaultArrangement constant
This constant is a string value that represents the arrangement style used by the IDE to order children controls inside a container
before saving them to disk.
The value can be one of the following string:
For example:
PUBLIC CONST _DefaultArrangement AS Integer = "V" ' Arrange.Vertical
That constant is only used if the control is a container, and is optional. If not defined, no arrangement is forced.
Control Icons
Each control must have an icon that will be displayed in the IDE control tool box.
To provide the icons of your component controls, you must create a
/control
directory at the root of your project,
and put one PNG file for each control icon in it.
In Gambas 3, the control
directory must be created inside the .hidden
directory. This is the "Project" section in the
development environment project treeview.
The name of a control icon must be the class name of the control
in lower case with the
.png
extension.
For example:
$ cd gb.db.form
$ cd .hidden/control
$ ls
databrowser.png datacombo.png datacontrol.png datasource.png datatree.png dataview.png
Component requirements
You can specify the component requirements in the "Information" tab of the IDE component property dialog.
In this tab, you will list all the dependencies of your component on other components.
The "Required features" section has five check-boxes, each one being a feature provided by one or many components.
You use this section when your component needs a specific feature, that does not rely on a specific component.
If you really need some specific components, you can select them in the "Required and excluded components" section of the tab.
You can exclude some components too. As soon as your component is used, these excluded components become unselectable.
The components that you select in the "Components" tab of the property dialog have nothing to do with
the components you specify in the "Required and excluded components" section.
They are only used when you run the component project from the IDE for debugging purpose.
Debugging, packaging and installing the component
Debugging
To debug your component, you can directly use and run its project as is!
The startup class of the project, and the components checked in
the "Components" tab of the project property dialog will not interfere at all with the behaviour of the component when it will be installed
and used by other projects.
Packaging
The IDE can make installation packages of your component, as it does for any other normal projects (Ctrl-Alt-I).
You just will have to define less options: a component has no menu entry, for example.
The installation package will install the component globally, and will be usable as any other official component provided by Gambas.
The name of the installation package will be composed as
gambas3-<vendor prefix>-<project name>
, so the name of your project must not include
the vendor prefix and the
gambas3
prefix.
For example, to create the package for the
gambas3-mycompany-foo
component, your project must be named
foo
, and
mycompany
must
be specified as
vendor prefix in the packager wizard.
At the moment, there is a flaw in the packager that does not take into account the component project version to generate the
package dependencies. Consequently, you have to set the version of your component project to the current Gambas version!
Installing
To install a component, an installation package supported by the target distribution must be created and applied. Currently these target distributions are supported by the packager wizard:
-
Archlinux
-
Autotools
-
Debian
-
Fedora / RedHat / CentOS
-
Mageia
-
OpenSUSE
-
Slackware
-
Ubuntu / Kubuntu / Mint
Conclusion
I try to find the easiest way of making components with the IDE. It is not perfect yet,
but if you have any comment, question or problem, please use the mailing-list!