Guiliani  Version 2.5 revision 6773 (build 33)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Widget library

Page contents

The Guiliani widget library

Guiliani comes with a set of predefined standard widgets. You can find a comprehensive list of these here: Controls
Feel free to use them as a basis for developing your own customized widgets, giving you complete freedom of design and behaviour.

Implementation details

In Guiliani all objects share a common base-class, which is CGUIObject. It includes everything vital to represent an object within a Guiliani application. This means elementary attributes, such as a position and size, as well as pre-defined event handling slots for reaction to user- or system events.

The advantage of having this common base-class is type-safety. Most of Guiliani's interfaces will work with CGUIObject's (or corresponding pointers) and thus ensure safe access to API's of this class. You can therefore safely do many of the most usual operations (such as moving or resizing objects, or changing the object hierarchy, or changing object states etc...) without having to know the exact type of the object that you are working on.

The second most common base-class is CGUICompositeObject - which is a generic container object. While itself inherits from CGUIObject, it enhances the generic interfaces by adding new attributes and methods which allow you to add child-objects to it, and to modify these. CGUICompositeObjects are thus used as a basis for developing container controls such as scrollable lists, ComboBoxes or draggable windows.

Writing your own controls

This section guides you through the process of writing your own simple control from scratch. In this example, we are going to implement a tiny control, which demonstrates the following features:

  • Deriving a customized widget from the Guiliani CGUIObject base-class
  • Implementing a customized drawing code
  • Implementing dragging functionality
  • Implementung a simple animation

The control will be named CDraggableDot. As the name implies, it will be visualized as a small, colored dot, and it can be dragged around the GUI by the user. Additionaly, we will implement an animation which lets the dot bounce off the borders of the GUI.

Let's have a look at the header file for this new control:

// Demo-implementation of a simple Guiliani control.
// This object behaves like a ball, which bounces off the screen borders.
// It visualizes itself by drawing a dot in an arbitrary color, and it
// implements basic dragging functionality.
class CDraggableDot
: public CGUIObject
{
public:
// Constructor
CDraggableDot(
CGUICompositeObject* const pParent,
const eC_Value& vX,
const eC_Value& vY,
const eC_Value& vWidth,
const eC_Value& vHeight,
const eC_UInt& uiColor,
const ObjectHandle_t& eID = NO_HANDLE);
// Destructor
virtual ~CDraggableDot();
// This method implements the object's visualization
eC_Bool DoDraw();
// This method will be called by the framework when the object is being dragged
eC_Bool DoDrag(const eC_Value &vDeltaX, const eC_Value &vDeltaY, const eC_Value &vAbsX, const eC_Value &vAbsY);
// This implements the object's animation
void DoAnimate( const eC_Value &vTimes = eC_FromInt(1));
private:
void Init();
eC_Value m_vDeltaX;
eC_Value m_vDeltaY;
eC_UInt m_uiColor;
};

You will notice that CDraggableDot inherits from CGUIObject - the common-base class of all Guiliani objects. The constructor expects a variety of parameters. Most of them are typical for any object within the GUI. Namely a position (in x,y pixel coordinates), a size and an object handle (an optional symbolic name). Additionaly there is a color parameter, which will allow the user to decide in which color the dot will visualize itself.

The DoDraw(), DoDrag() and DoAnimate() methods are standardized slots which were inherited from CGUIObject, and that will be called by the framework when the object should draw itself (DoDraw), when it receives a dragging event (DoDrag) or periodically when it is animating itself (DoAnimate). We will have a closer look at those soon.

Finally, there are some private attributes which the object will use internally to store its current state. In this case these are movement delta's in x/y direction for the animation, plus the aforementioned color value.

The above interfaces are implemented within the control's cpp file as follows:

CDraggableDot::CDraggableDot(
CGUICompositeObject* const pParent,
const eC_Value& vX,
const eC_Value& vY,
const eC_Value& vWidth,
const eC_Value& vHeight,
const eC_UInt& uiColor,
const ObjectHandle_t& eID)
: CGUIObject( pParent, vX, vY, vWidth, vHeight, eID),
m_uiColor( uiColor)
{
Init();
}

The constructor is trivial. All it does, is to forward the supplied parameters to the base class CGUIObject and to invoke some internal initialization...

void CDraggableDot::Init()
{
// initialize defaults
// This class shall not be focussable using the keyboard
SetFocussable(false);
// movement direction initialization
m_vDeltaX = eC_FromInt(0);
m_vDeltaY = eC_FromInt(0);
// Animate this control
GETTIMER.AddAnimationCallback( 30, this);
}

This routine takes care of initializing the private member attributes with sensible values, setting the object to non-focussable (because we do not want it to be focussable via the keyboard. All we want is to drag it.) and registering an Animaton Callback for this object. The GETTIMER helper macro grants you access to the framework's internal timer, so that you can request your animation code to be executed every 30 milliseconds.

CDraggableDot::~CDraggableDot()
{
// if this control gets destroyed, stop animation
GETTIMER.RemoveAnimationCallback( this);
}

Once the object gets destroyed, we unregister the animation callback. All other required de-initialization, such as for example removing the object from its parent's list of children, happens within the base class already.

eC_Bool CDraggableDot::DoDraw()
{
GETGFX.SetForegroundColor( m_uiColor);
GETGFX.Ellipse( GetAbsRect(), true);
return true;
}

This small source code snippet is the drawing code of the control. It will be called whenever the framework detects that it overlaps with a region of the GUI that is in need of a redraw. Note that the GETGFX helper macro is used to access the platform independant graphics layer of Guiliani. This means that this code will work regardless of which graphics API will be used to draw this on a given target platform later on. This method simply sets the foreground color to the color value which we received during construction, and tells the graphics wrapper to draw a filled ellipse at the object's current position.

eC_Bool CDraggableDot::DoDrag(const eC_Value &vDeltaX, const eC_Value &vDeltaY, const eC_Value &vAbsX, const eC_Value &vAbsY)
{
// Move the object along with the mouse
InvalidateArea();
// vDelta is the relative mouse movement since the last event
SetRelXPos( GetRelXPos() + vDeltaX);
SetRelYPos( GetRelYPos() + vDeltaY);
InvalidateArea();
// And adapt its moving-direction accordinly
m_vDeltaX = vDeltaX;
m_vDeltaY = vDeltaY;
return true;
}

This code adds the dragging functionality to our control. You can see how the position of the object gets updated with the dragging offsett which we receive via the parameters from the framework. Noteworthy are the InvalidateArea() calls. Those tell the framework that the area covered by this object needs to be redrawn. You will need to call this method whenever something changes the visualization of your control - like e.g. its position, its size, its color etc. Finally we update the movement vector with the most recent dragging direction. This will let the dot fly into the direction into which we last dragged it.

void CDraggableDot::DoAnimate( const eC_Value &vTimes)
{
InvalidateArea();
eC_Value vX = GetRelXPos();
eC_Value vY = GetRelYPos();
// The following lines make the object bounce off the borders of the parent object
if( ((vX <= 0) && m_vDeltaX < 0) || // object moves right and is too far right
((vX >= GETGUI.GetWidth() - GetWidth()) && m_vDeltaX > 0) ) // moves left and is too far left
{
m_vDeltaX = eC_Mul( m_vDeltaX, eC_FromInt(-1));
}
if( ((vY <= 0) && m_vDeltaY < 0) || // object moves up and is above upper border
((vY >= GETGUI.GetHeight() - GetHeight()) && m_vDeltaY > 0) ) // moves down and is below lower border
{
m_vDeltaY = eC_Mul( m_vDeltaY, eC_FromInt(-1));
}
// Update position
SetRelXPos( GetRelXPos() + eC_Mul( m_vDeltaX, vTimes));
SetRelYPos( GetRelYPos() + eC_Mul( m_vDeltaY, vTimes));
// Request redraw for area which is covered by the object
InvalidateArea();
}

The DoAnimate() method implements the animation for our control. The code inside is mostly some calculations to detect whether we have moved out of the GUI's area. If that is the case, the movement direction gets inverted, making the object bounce off the respective border. What you need to know about DoAnimate() methods are mostly three things:

  • They will be called cyclically by the framework. You can set the time interval while registering the animation callback.
  • The vTimes parameter is a factor indicating how much time has actually passed since the last callback. If you did for instance request a callback to occur every 30ms, but for some reason it took 60ms until it actually came, then vTimes will be 2. This is to allow for animations to run at a constant speed - independant of the target hardware.
  • Do not forget to call InvalidateArea() or you will not see anything of your fancy animation!