Resources | developer.brewmp.com Resources | developer.brewmp.com

Developer

resources

Creating a custom widget

Base version:

Brew MP 1.0

Tested version:

Brew MP 1.0

Phone tested:

No

This document describes how to create a custom widget to use in widget-based applications. Modifying the Brew® MP UI Widgets code is strongly discouraged. Instead, it is recommended that your own widgets be implemented outside of Brew MP UI Widgets in their own extension.

Objective

This document explains how custom widgets can be created by using widgets from the Brew MP UI Widgets platform. The custom widget implemented is a CheckBoxStatic Widget, consisting of both a text label and a radio button. Prop container is used as a base widget to implement this widget. Prop container has a checkbox and static Widget inserted in it. This creates the basic look and feel of the CheckBoxStatic widget. This example overrides the event handler for custom event handling.

A model is needed to store the data associated with this widget. The CheckBoxStatic widget has a value model attached to it that uses the CheckBoxStaticWidget_ModelData as the model. CheckBoxStaticWidget_ModelData has two members, the text that can be used by the label, and checkState to denote whether checkbox is enabled or not.

Requirements

To create a CheckBoxStatic Widget, you need to create an extension using existing Brew MP UI Widgets. The following steps provide an overview of what needs to be done. Each step is described in more details in the examples. For more information on Brew MP extensions, see the C Extension Visual Studio Primer.

  1. Create a public header file for CheckBoxStatic Widget.
  2. Define the internal structure of the widget.
  3. Update a CheckBoxStatic_New function.
  4. Property handling.
  5. Freeing memory.

Sample code location

ZIP filename

Location

Run app

c_checkboxstaticwidget_app

Brew MP Resources

  • Download and extract the ZIP file.

  • Compile the app.

  • Run it on the Brew MP Simulator.

c_checkboxstaticwidget_extension

Brew MP Resources

  • Download and extract the ZIP file.

  • Compile the app.

  • Run it on the Brew MP Simulator.

Example: create a public header file for CheckBoxStatic widget

The header file defines the model data associated with CheckBoxStatic widget. It also defines a property to configure this widget to use radio buttons instead of a check box. It defines two other properties, PROPEX_CHECKBOXSTATICWIDGET_CHECKWIDGET and PROPEX_CHECKBOXSTATICWIDGET_STATICWIDGET, to retrieve check box and static widgets from CheckBoxStatic Widget. CheckBoxStatic widget is implementing the IWidget interface, so CheckBoxStatic widget does not have an interface definition in the public header file.

typedef struct CheckBoxStaticWidget_ModelData          
{          
   const AECHAR*  pwszLabel;   // Label for the check box          
   boolean        bCheckState; // Whether its checked or not.          
} CheckBoxStaticWidget_ModelData;               
           
// Property to use the radio button instead of a check box.          
#define  PROPEX_CHECKBOXSTATICWIDGET_RADIOBUTTON       0x0108bfa8          
           
// Property to get the radio button/check box widget form CheckBoxStatic Widget.          
#define  PROPEX_CHECKBOXSTATICWIDGET_CHECKWIDGET       0x0108d1c7          
           
// Property to get the static widget form CheckBoxStatic Widget.          
#define  PROPEX_CHECKBOXSTATICWIDGET_STATICWIDGET      0x0108d1c8          
           
static __inline int IWidget_GetCheckBoxStaticCheckBoxWidget(IWidget *pif,           
                                               IWidget **ppiwCheckBox) {          
   return IWidget_GetPropertyEx(pif, PROPEX_CHECKBOXSTATICWIDGET_CHECKWIDGET,           
                        (int)sizeof(*ppiwCheckBox), (void*)ppiwCheckBox);          
}          
           
static __inline int IWidget_GetCheckBoxStaticStaticWidget(IWidget *pif,           
                                               IWidget **ppiwCheckBox) {          
   return IWidget_GetPropertyEx(pif, PROPEX_CHECKBOXSTATICWIDGET_STATICWIDGET,           
                        (int)sizeof(*ppiwCheckBox), (void*)ppiwCheckBox);          
}

Example: define the internal structure of the widget

The following structure is used by CheckBoxStatic Widget. It creates a prop container and uses it as the base widget. It has two additional widgets to store the check box and static widget. It provides extra property handling by overriding the handler of prop container. It also has a model listener for the view and value model of the widget.

typedef struct {          
   IModule        *piModule;          
   IEnv           *piEnv;          
   IWidget        *piwBase;        // Widget of prop container          
   IPropContainer *picBase;        // Propcontainer ref          
   IWidget        *piwCheckBox;    // Checkbox          
   IWidget        *piwLabel;       // Label          
   HandlerDesc    hdWidget;        // Handler for prop container             
            
   // Model Listeners          
   ModelListener  mlValueModel; // Value model Listener          
   ModelListener  mlViewModel;  // View model listener so we know if the widget          
                                // changes its value model.          
} CheckBoxStaticWidget;

Example: update a CheckBoxStatic_New function

The following code snippet shows how to create CheckboxStatic Widget with existing widgets. It first creates an instance of prop container, then creates checkbox and static widget, and inserts those widgets in prop container. It creates a value model and attaches a listener and the view model to the value model. It overrides the prop container's event handler for handling properties for this widget.

int CheckBoxStaticWidget_New(IWidget **ppOut, IShell *piShell, IModule *piModule)          
{          
   c_checkboxstaticwidget_extension *me = NULL;          
   IPropContainer       *piPropContainer = NULL;          
   IWidget              *piWidget = NULL;          
   IModel               *pim = NULL;          
   IEnv                 *piEnv = NULL;          
   int                  nErr = AEE_EFAILED;          
            
   ERR_TRY( ISHELL_CreateInstance(piShell, AEECLSID_Env, (void **) &piEnv) );          
   ERR_TRY( IENV_ERRMALLOCREC(piEnv, c_checkboxstaticwidget_extension,           
                                                            (void **) &me) );          
   me->piEnv = piEnv;          
   IEnv_AddRef(piEnv);          
   me->piModule = piModule;          
   IMODULE_AddRef(piModule);          
            
   // Create a prop container and insert StaticWidget and Checkbox                
   nErr = IEnv_CreateInstance(piEnv, AEECLSID_PropContainer, (void **)           
                                                           &piPropContainer);          
   if (nErr != AEE_SUCCESS) {          
      CheckBoxStaticWidget_Dtor(me);          
      return nErr;          
   }          
   ERR_TRY( IPropContainer_QueryInterface(piPropContainer, AEEIID_IWidget,           
                                                      (void **) &piWidget) );

Note that the first picBase and piwBase are stored with a 'weak' reference (no increment of the reference count). This is because the CheckBoxStatic widget is overriding the event handler and attaching a value model to the base container. PicBase and piwBase will be destroyed and freed whenever the container is destroyed. Since it is essentially a self reference, that's why there is no need to count it in the reference counting.

   me->picBase = piPropContainer;          
   me->piwBase = piWidget;            // No addref                
   // Set layout style to horizontal          
   ERR_TRY(  IWidget_SetLayoutStyle(piWidget, AEEWIDGET_LAYOUT_HORZ) );          
   // Set border properties          
   ERR_TRY(  IWidget_SetBorderWidth(piWidget, 0) );          
   ERR_TRY(  CheckBoxStaticWidget_AddStaticWidget(me) );          
   ERR_TRY(  CheckBoxStaticWidget_AddCheckBox(me, TRUE) );   

Attach model listeners to the base widget.

    // View Model Listener          
   ModelListener_InitEx(&me->mlViewModel,           
                    (PFNLISTENER)CheckBoxStaticWidget_ViewModelListener, me);          
   ERR_TRY( IWidget_GetViewModel(piWidget, &pim) );          
   ERR_TRY( IModel_AddListener(pim, &me->mlViewModel) );          
   RELEASEIF(pim);          
             
   // Value Model Listener            
   // This listener will be automatically attached by the View Model Listener          
   // Callback when the value model is attached           
   // Create the value model to attach to the base widget          
   ERR_TRY( IEnv_CreateInstance(piEnv, AEECLSID_ValueModel, (void**) &pim) );          
   ModelListener_InitEx(&me->mlValueModel,           
                   (PFNLISTENER)CheckBoxStaticWidget_ValueModelListener, me);          
   ERR_TRY( IWidget_SetModel(piWidget, pim) );

Set the custom handler for this widget, because this widget does custom property handling.

   HANDLERDESC_INIT(&me->hdWidget, CheckBoxStaticWidget_HandleEvent, me,           
                                                  CheckBoxStaticWidget_Dtor);          
   IWidget_SetHandler(piWidget, &me->hdWidget);          
            
   *ppOut = (void *)me->piwBase;          
          
   ERR_CATCH:             
      RELEASEIF(piPropContainer);    // Release the prop container          
                                     // it has only a weak reference           
      RELEASEIF(pim);          
      RELEASEIF(piEnv);          
   return nErr;          
}

Example: property handling

In the handle event function, this widget handles PROPEX_CHECKBOXSTATICWDGT_RADIOBUTTON property to toggle between radio button and checkbox. It passes all the other events to prop container's event handler.

c_checkboxstaticwidget_extension *me = (c_checkboxstaticwidget_extension *) pCxt;          
boolean handled;          
            
switch (eCode) {          
   case EVT_WDG_SETPROPERTY:          
      if (PROP_EX == wParam) {          
         WidgetPropEx *pPropEx = (WidgetPropEx*) dwParam;          
         if (pPropEx->nPropId == PROPEX_CHECKBOXSTATICWIDGET_RADIOBUTTON) {          
            int nErr = 0;          
            nErr = CheckBoxStaticWidget_AddCheckBox(me,
                        (uint32) pPropEx->pUser ? TRUE : FALSE);          
            return (SUCCESS == nErr);          
         }          
      }           
      break;          
   case EVT_WDG_GETPROPERTY:          
      if (PROP_EX == wParam) {          
         WidgetPropEx *pPropEx = (WidgetPropEx*) dwParam;          
         if (pPropEx->nPropId == PROPEX_CHECKBOXSTATICWIDGET_CHECKWIDGET) {          
            *((IWidget**) pPropEx->pUser) = me->piwCheckBox;          
            ADDREFIF(me->piwCheckBox);          
            return TRUE;          
         }           
         else if (pPropEx->nPropId == PROPEX_CHECKBOXSTATICWIDGET_STATICWIDGET) {          
            *((IWidget**) pPropEx->pUser) = me->piwLabel;          
            ADDREFIF(me->piwLabel);          
            return TRUE;          
         }          
      }            
      break;                                                                                                                                                                                                                   
   default:          
   break;          
}          
handled =  HANDLERDESC_CALL(&me->hdWidget, eCode, wParam, dwParam);

Example: freeing memory

The following code cancels the listeners, frees the handler and releases the widgets.:

c_checkboxstaticwidget_extension *me = (c_checkboxstaticwidget_extension *) pCxt;          
            
// Cancel Listeners          
LISTENER_Cancel(&me->mlValueModel);          
LISTENER_Cancel(&me->mlViewModel);          
            
// Free handler          
HANDLERDESC_FREE(&me->hdWidget);          
            
// Release Widgets          
RELEASEIF(me->piwCheckBox);          
RELEASEIF(me->piwLabel);          
{          
   IEnv *piEnv = me->piEnv;          
   me->piEnv = NULL;          
   IMODULE_Release(me->piModule);          
   (void) IEnv_Free(piEnv, me);          
   IEnv_Release(piEnv);          
}

Related information

  • See the Widgets Technology Guide
  • See the C Extension Visual Studio Primer