company logo

User-defined control styles

The GUI framework supports user-defined control styles, i.e. control styled defined by external users. User controls have to be defined as Qt controls, i.e. those have to be developed using Qt GUI library.

User controls are provided in a separated dynamic library, which supports a defined interface for user controls described in the UserControl interface class. The Control type name corresponds to the name of the user control library without the platform specific extensions. E.g. the user control library for the user control MyControl has to be provided in a libMyControl.so (Linux) or MyControl.dll (Windows) library.

In order to ignore the fact, that a user control could not be loaded, Optional could be set to true. In order to make use of different control specific features not supported by the GUI frame work, specific control options can be defined in Control options. The way to pass those options depend on the implementation of the user control, which receives all optional settings in a single options string. In general, it is suggested to use keyword options separated by line breaks, which increases readability for options. Options supported by a specific user control are defined in the user control documentation, which should be delivered with the binaries.

We will add user control of common interest to GUI framework controls delivered with the GUI frame work, when the controls fulfill the requirements for documentation and the common syntax conventions for control options as described above.

Principles

User controls communicate via a user control handle with the GUI frame work. Each user control inherits from UserControl, which provides a property function controlHandle() that points to a UserControlHandle instance within the GUI framework. The UserControlHandle provides a property() function, which returns the data source for the user control as odaba::Property. Data to be displayed/processed in the user control can be obtained from the data source property handle.

The user control also may update data in the data source calling appropriate odaba::Property functions. Changes in the data source are signaled immediately to the GUI framework. On the other side, the GUI framework submits a few messages to the user control.

  • activate() and deactivate() event handler are called when a user control becomes active (has been opened) or inactive (being closed). Usually, when calling those handlers, no data source is available.
  • propertOpened(), propertyClosed() and propertyActivated() signal import state changes for the data source. When changing the data source for a user control, at least propertyActivated() is signaled. After the property has been activated, data can be obtained from the data source via the property handle.
  • fillData() and clearData() are GUI framework requests, which result from state changes in the property handle. Typically, fillData() is called when an instance has been selected in a property handle, or when it has been updated or created. clearData() is called, when the instance in a property handle has been unselected or deleted.

The user control has to provide a widget() function, which returns the control widget (QWidget) for the user control. The control widget receives appropriate GUI events and should be the main widget representing the user control (when the user control consists of more than one widget).

Since the widget is registered in the user control parent and deleted when deleting the parent, the control widget created in within the user control should not be deleted when the user control is destructed. Otherwise, it may be destructed twice, which causes abnormal program termination.

Implement a user control

Implementing a user control requires the user control class which inherits from UserControl and a static createControl() function, which is called from the user control library in order to create the control. The calling conventions for the createControl() function are defined in the cUserControl.h header file (see example below). The createControl() function just created the user control object and returns a pointer to it to the GUI framework.

The minimum for implementing a user control class is inheriting from UserControl and implementing the widget() function, which has to be implemented explicitly. The complete user control interface is defined in the UserControl.h header file (see also "User Control Interface")

// cUserControl.h

#undef  UC_ImpExp

#ifdef  __unix__

#define UC_ImpExp

#else

#define UC_ImpExp __declspec(dllexport)

#endif

#pragma once

class UserControl;

class UserControlHandle;

class QWidget;

#if defined (__cplusplus)

  extern "C" {

#endif

UC_ImpExp     UserControl *__cdecl createControl ( UserControlHandle *, QWidget *);

#if defined (__cplusplus)

             }

#endif

// Sample implementation

#include  <cUserControl.h>

#include  <MyControl.hpp>

UserControl* createControl(UserControlHandle *c_handle, QWidget* parent) {

    return new MyControl(c_handle,parent);

}

User control features

User controls are supported by common GUI framework features. Thus, user controls might be connected with any type of data source. They are automatically updating according to the instance selected in the user control data source and signal data changes. In order to present the data properly in the user control area, the user control may request the data source from the user control handle (property()).

When changing the property handle state in the property handle returned by the UserControlHandle::property() function, changes are signaled to the GUI framework, which will react by updating other controls referring to the same data source. In order to avoid this, for temporarily action as iterating through a collection, a cursor copy should be created for the property handle (Property::cursorCopy())

Build User control interface

The complete user control interface definition is available in the cUserControl.hpp header file, which is shown below (without comments). The header file is delivered in the odaba/include directory. In order to be able to load the user control, it has to be provided in a user control library, which exports a createControl() function as declared below. The function creates a user control and returns the pointer to the caller. The UserControlHandle managing the control is passed to the creator function as well as the parent widget (QWidget). User control specific parameters are passed in the third control as 0-terminated string. The way parameters are provided depends on the user control specification made by the developer. Keyword parameters separated by line breaks are suggested.

Virtual functions defined in the interface have to be exported (Windows) in order to be accessible from the GUI framework.

The UserControlHandle class provides a simple interface for accessing resources provided by the GUI framework. In this version, the data source for the control can be accessed via the UserControlHandle. Further resources might be added in future.

After implementing user control functions, the user control has to be linked into a separate library with the given name of the user control. Depending on the operation system, the library name has to be extended by system specific extensions, as MyControl becomes:

libMyControl.so (Linux)

MyControl.dll (Windows)

In order to link the user control library, the GUI framework library is required (libogui.so/ogui.dll), which is provided in the odaba/lib directory.

#undef  UC_ImpExp

#ifdef  __unix__

#define UC_ImpExp

#else

#define UC_ImpExp __declspec(dllexport)

#endif

#pragma once

class OUserControl;

class QWidget;

namespace odaba { class Property; }

class  UserControlHandle

{

private    :         OUserControl                                *ouser_control;                                             //

public     :                  UC_ImpExp            odaba::Property *property ( );

};

class  UserControl

{

protected  :         UserControlHandle                           *control_handle;                                            //

public     :                  UC_ImpExp                 UserControl (UserControlHandle *pUserControlHandle );

public     :                  UC_ImpExp                 UserControl ( );

public     : virtual          UC_ImpExp                 ~UserControl ( );

public     : virtual          UC_ImpExp            QWidget *widget ( );

public     :                  UC_ImpExp            UserControlHandle *controlHandle ( );

public     :                  UC_ImpExp            void controlHandle (UserControlHandle *pUserControlHandle );

public     : virtual          UC_ImpExp            void activate ( );

public     : virtual          UC_ImpExp            void deactivate ( );

public     : virtual          UC_ImpExp            void clearData ( );

public     : virtual          UC_ImpExp            void fillData ( );

public     : virtual          UC_ImpExp            void propertyActivated ( );

public     : virtual          UC_ImpExp            void propertyClosed ( );

public     : virtual          UC_ImpExp            void propertyOpened ( );

};

#if defined (__cplusplus)

  extern "C" {

#endif

UC_ImpExp     UserControl *__cdecl createControl ( UserControlHandle *, QWidget *, const char *);

#if defined (__cplusplus)

             }

#endif

User control documentation

In order to publish a user control, the following topics have to be described in the user control documentation:

  • Name - User control name
  • Title - short characteristic of the control
  • Features - Documentation of control features
  • Usage - Hints for using the control in an application
  • Implementation - Describing specific parameters to be defined in the control style definition
  • Resources - additional resources required for building and using the control
  • User hints - hints for people using the control

User controls provided with source code and sufficient documentation might be added to the GUI framework user control library.

Communication

In order to communicate with the context classes, which might be installed for user controls similar to ordinary ones, message functions are provided on both sides. Thus, the application may receive and send messages from/to a user control. Supported commands for a user control are defined for each user control separately. Typically, a message contains a command and optional parameters:

    command[:parm1;parm2...]

Parameters are separated by semicolon. When a parameter contains a semicolon, it has to be quoted ("..."). Quotes at beginning and end of a parameter string are removed. This is just a suggestion. In principle, any string format may be defined by the user control developer.

Receive messages from user control

In order to pass information from the user control to a context class instance, the UserControlHandle::message() function may be called. For receiving messages sent by the user control, the GUIBaseContext::doMessage() handler has to be reimplemented in the context class. In order to obtain the message text, GUIBaseContext::getMessage() may be called.

// pass message to context class

// User control function (C++)

// control_handle a member of UserControl base class

... My_UserControl :: function () {

  control_handle->message("previous");

}

// OSI context function

// called, when message has been submitted from user control

int32 myContextClass :: doMessage {

  switch ( getMessage() ) {

    case "auto"     :

    case "next"     : nextElement();     break;

    case "previous" : previousElement(); break;

    case "end"      : stopProcessing();  break;

  }

}

Submit messages to user control

In order to send commands or data (messages) to the user control, the context function GUIBaseContext::message() may be called. For obtaining messages in the user control, the user control has to re-implement the UserControl::message() function.

// send message to user control

// User control function (C++)

// OSI user control context function

... myContextClass::function {

//...

  message("start"); // start playing the movie

//...

}

// re-implemented message function in user control

void My_UserControl :: message (const char *string ) {

  if ( !strcmp(string,"start") )

    StartMovie();

  else if ( !strcmp(string,"stop") )

    StopMovie();

}