Resources | Resources |



Adding a draw handler to a widget

This topic describes how to adding a custom draw handler to a widget, allowing an application to hook a custom drawing routine into the default draw operation normally invoked for a widget. The example code shown in this topic is from c_widgetsampledrawhandler_app.


Draw handlers are called in first-in, last-out order, which means that the application's draw function is called before the widget can draw itself. The application can decide to what to do before or after calling the widget's draw function, and may even decide to skip drawing the widget.

The example shows very basic buffer modification, both before and after the widget's default drawing, and also implements minimal data gathering for an FPS counter.


To attach a draw handler to a widget, an application needs to do the following:

  1. Write a draw function.
  2. Create the desired widget.
  3. Query the widget for its IDrawHandler() function.
  4. Create and initialize a draw handler descriptor.
  5. Apply the descriptor to the widget through its IDrawHandler interface.

An application that wishes to detach a draw handler may do so via a call to DrawHandlerDesc_Free().

Example: structure and function definitions

To provide a custom draw handler, an application must include additional header files, and add a field to its private structure, as follows:

#include “AEEIDrawHandler.h"    
typedef struct _c_widgetsampledrawhandler_app {    
   /* struct definition of app*/    
   //Widget variables    
   IRootContainer   *picRoot;    
   IWidget          *piwRoot;    
   IWidget          *piw;    
   //DrawHandler Variables    
   DrawHandlerDesc  drawdesc;    
   uint32           nFrameCount;    
   uint32           nPreviousDrawTime;    
   uint32           nTimeElapsed;    
} c_widgetsampledrawhandler_app;    
void c_widgetsampledrawhandler_app_Draw(c_widgetsampledrawhandler_app *pMe,     
            ICanvas *piCanvas, int x, int y);    
void c_widgetsampledrawhandler_app_DrawHandlerFree(c_widgetsampledrawhandler_app     

Example: initializing the draw handler

Though the draw handler can be overridden at any point in time, it is most likely to occur on widget creation. To attach a draw handler, initialize the draw handler descriptor and set it to the widget via its IDrawHandler interface.

static int c_widgetsampledrawhandler_app_InitWidgets(c_widgetsampledrawhandler_app    
   int nErr = 0;    
   WidgetPos WidPos = {0};    
   WidgetExtent we = {0};    
   IDrawHandler *piDrawHandler = NULL;    
   ERR_TRY( c_widgetsampledrawhandler_app_SetupRootContainer(pMe) );    
   // Create widget    
   ERR_TRY( ISHELL_CreateInstance(pMe->pIShell, AEECLSID_CStaticWidget,     
                                                (void**) &pMe->piw) );    
   we.height = 24;    
   we.width = 100;    
   (void) IWidget_SetBGColor(pMe->piw, MAKE_RGBA(0,183,229,200));    
   IWidget_SetExtent(pMe->piw, &we);    
   // Insert it into RootContainer    
   WidPos.bVisible = TRUE;    
   WidPos.x = (pMe->DeviceInfo.cxScreen / 2 - we.width) / 2;    
   WidPos.y = (pMe->DeviceInfo.cyScreen / 2 - we.height) / 2;    
   (void) IRootContainer_Insert(pMe->picRoot, pMe->piw,
               WIDGET_ZNORMAL, &WidPos);

The following code demonstrates draw handler and data variables initialization.

  //Query for the draw handler    
  ERR_TRY(IWidget_QueryInterface(pMe->piw, AEEIID_IDrawHandler,     
                       (void **)&piDrawHandler));    
  DrawHandlerDesc_Init(&pMe->drawdesc, c_widgetsampledrawhandler_app_Draw,
  IDrawHandler_SetDraw(piDrawHandler, &pMe->drawdesc);    
  pMe->nFrameCount = 0;    
  pMe->nPreviousDrawTime = 0;    
  pMe->nTimeElapsed = 0;

The following code is cleanup.

   return nErr;    

Example: draw function

The application must provide the draw function that will be called each time the widget is drawn.

void c_widgetsampledrawhandler_app_Draw(c_widgetsampledrawhandler_app *pMe,     
            ICanvas *piCanvas, int x, int y)    

The following segment demonstrates buffer modifications prior to drawing the widget, to draw two lines under the widget. Since the background color is partially-transparent, the lines are still visible.

  IDISPLAY_DrawHLine(pMe->pIDisplay, x, y+4, 75);    
  IDISPLAY_DrawHLine(pMe->pIDisplay, x, y+20, 75);

Call the widget's default draw.

   DrawHandlerDesc_Call(&pMe->drawdesc, piCanvas, x, y);

The following code modifies the buffer after drawing the widget to draw two more lines over the widget.

  IDISPLAY_DrawHLine(pMe->pIDisplay, x+25, y+9, 75);    
  IDISPLAY_DrawHLine(pMe->pIDisplay, x+25, y+15, 75);

Data gathering for FPS counter.

  pMe->nFrameCount ++;    
  pMe->nTimeElapsed = GETUPTIMEMS() - pMe->nPreviousDrawTime;    
  pMe->nPreviousDrawTime = GETUPTIMEMS();    

Example: cleanup

The application must provide a _Free() function that will cleanly detach the handler from the drawing cycle.

  void c_widgetsampledrawhandler_app_DrawHandlerFree    
               (c_widgetsampledrawhandler_app *pMe){