Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Low-Level Management of Multi-Control Screens Under BREW

In this tutorial you'll add power and flexibility to your BREW apps by learning how to code your own low-level navigation for a collection of BREW controls on a single screen of a device.


advertisement

Most BREW applications require some kind of user interface, consisting of various screens. A developer essentially has two choices when confronted with the task of implementing any screen design:

1.) Use a dialog to contain the required controls, and live with the dialogs somewhat restrictive nature, or

2.) Fly without a net, using only the controls themselves.



In this article, youll learn how to implement the latter option, the most flexible and powerful of the two approaches.

The application we're going to cover consists of a generic user-interface (UI), and nothing more. The intent is to show you how to code your own, low-level navigation for a collection of BREW controls residing on a single screen. Specifically, our single screen UI will consist of 3 text controls and a related soft key menu residing at the bottom of the screen.

When we're done and we run it on the emulator, the application should appear exactly as shown in Figure 1, when it opens. As you can see, you really can fit more than one control on a single screen and still get a reasonably attractive result. As you might have guessed, the rectangle surrounding the first control indicates that it currently has the input focus.

Figure 1

What you need to get started
The example contained herein assumes the use of BREW SDK 1.x and BREW Emulator version 2.0.0.38. If you intend to work along with the example, you must create a module information file, consistent with the file / directory naming scheme covered in the SDK User's Guide. Copy this file to ...yourBREWdir\Examples\mif\256Color\, or to whatever directory you've chosen to designate as your mif directory within the BREW Emulator. For more information, please consult the BREW SDK User's Guide provided with the BREW SDK.

For ease of exposition, I've hard-coded the required strings in the application's source file. I really should have used the BREW Resource Editor to create a resource file containing all of the strings used in the application. ISHELL_LoadResString() would then be used to programmatically retrieve each of these strings from the resource file. For more information on using the Resource Editor and the ISHELL_LoadResString() function, please see "The BREW Resource Editor Guide" and "The BREW API Reference", respectively. Both of these documents are included with the BREW SDK.

How screen navigation works
As you will see, when the developer assumes control over screen navigation, (s)he can specify the means by which this navigation should take place. Both a text control and a soft key menu provide default behaviors in response to left and right key presses. A text control responds by moving the insertion point (i.e. the cursor) left or right within thetext string. By default, a left key press has no effect if the insertion point is already at the front of the string and a right key press has no effect if the insertion point is at the end of the string. We will alter this default behavior.

The soft key menu moves the current command selection to the menu item on the immediate left or right, consistent with the key pressed. Note that plain menus and list controls (please see the SDK User's guide) exhibit this item selection behavior in response to the up and down keys, while the select, left and right keys, are typically used for moving between menus on the same screen. We'll learn more about this when we examine dialogs in a later article.

Intuitively, within the UI shown in Figure 1, a user should move from control to control by thumbing the up or down arrow keys. This scheme is my personal favorite as it dovetails nicely with the actual layout and default functioning of the controls. The BREW User Interface Design Guidelines provide some excellent advice on this subject and a developer would be well advised to read through this document before starting to code an application's UI.Thus, to be consistent with the guidelines, and avoid conflicting with the default behavior of the various controls, it appears that we must navigate by means of the up and down keys. An example of such an implementation is included in the archive file available for download at the end of this article.

A recent post in the BREW Developers' Forum sought advice on how to navigate a UI similar to the one shown in Figure 1. Apparently the poster was required to use the left and right arrow keys to move from text control to text control, and from text control 3 to the menu. Since this is more of a challenge, and thus more interesting than implementing the up and down solution, we will code this unusual case. Before we start, you should note that this solution runs contrary to the spirit, if not the letter, of the BREW User Interface Design Guidelines.

In the case of the menu control, the left and right keys change the menu selection exclusively. Separate soft key items are provided so that the user can directly move from the menu control to any of the text controls . Clearly, it might be desirable to permit the user to move from the menu to either text control 1 or text control 3 by using the down or up key, respectively. Note that this functionality is included in the alternate source file mentioned above.

Clearly stated, our goal is to provide a user interface consisting of 3 text controls and a soft key menu. The user navigation scheme is summarized in the following two tables:

  Active Text Control
Key Pressed Text Control 1 (Txt1) Text Control 2 (Txt2) Text Control 3 (Txt3)
AVK_LEFT If cursor is not at front of string, move cursor to left within string. If cursor is at front of string, move focus to Txt1. Else, move cursor to left within string. If cursor is at front of string, move focus to Txt2. Else, move cursor to left within string.
AVK_RIGHT If cursor at end of string, move focus to Txt2. Else, move cursor to right within string. If cursor at end of string, move focus to Txt3. Else, move cursor to right within string. If cursor at end of string, move focus to Soft Key. Else, move cursor to right within string.
AVK_CLR If cursor at front of string, ITEXTCTL_HandleEvent() will cause application to exit. Else, it will delete character to left of cursor.
AVK_END

Exit Application. AVK_END is automatically handled by the Application Execution Environment (AEE)

 

ITEXTCTL_HandleEvent() automatically moves the cursor within the string and handles AVK_CLR (clear key). In short, to realize this default behavior, pass the related events to ITEXTCTL_HandleEvent(). The programmer must handle moving the focus between controls.

The emulator showed this behavior while the same code running on a Sharp Z800 handset did not. Other handsets were not tested.

 

Selected Soft Key Menu Item

Key Pressed

Edit One Edit Two Edit Three Exit
AVK_LEFT

Handled by IMENUCTL_HandleEvent(). Moves menu selection left or right.

AVK_RIGHT
AVK_SELECT

Move focus to indicated text control in EVT_COMMAND handler for menu item associated with key press.

Exit Application

AVK_CLR

Exit application. Programmer must return FALSE from EVT_KEY's AVK_CLR handler.

AVK_END

Exit application. AVK_END is automatically handled by the Application Execution Environment (AEE).

Now let's walk through the code:


#include "AEEModGen.h"          // Module interface definitions
#include "AEEAppGen.h"          // Applet interface definitions
#include "AEEShell.h"           // Shell interface definitions
#include "AEEMenu.h"
#include "AEEText.h"
#include "AEEStdLib.h"
#include "screenapp.bid"

// menu item IDs
#define IDLI_ONE      1
#define IDLI_TWO      2
#define IDLI_THREE   3
#define IDLI_EXIT      4

// screen layout parameters
#define TEXT_X_ORIGIN 5
#define TEXT_X_WIDTH 100
#define VERT_SPC 10
#define FONT_PAD 2

#define MAX_TXT_LEN   255   // MAX number of characters in ITextCtl

typedef struct _txtctl
{
   ITextCtl *m_ptxtctl;
   byte m_spcToEnd;   // num spaces to end of txt ctl's string (cursor location)
} txtctl;

typedef struct _screenapp
{
   AEEApplet a;
   IMenuCtl *m_pMnu;
   txtctl m_Txt1;
   txtctl m_Txt2;
   txtctl m_Txt3;
   txtctl *m_pActiveTxt;   // tracks currently active textctl
} screenapp;

/*-------------------------------------------------------------------
Function Prototypes
-------------------------------------------------------------------*/
static boolean screen_HandleEvent(IApplet * pi, AEEEvent eCode, 
        uint16 wParam, uint32 dwParam);
static boolean initData(screenapp *papp);
static void closeapp(screenapp *papp);

Once we get past the #includes and #defines, the first interesting part we come to is the typedef for txtctl. As you can see, a txtctl consists of a pointer to an ITextCtl and a single byte used to track the position of the cursor within each of the text controls in our UI. In BREW 1.X, there is no API function to supply the developer with the current cursor position (BREW 2.0 has ITEXTCTL_GetCursorPos()). The m_spcToEnd member is necessary since each ITextCtl instance remembers the location of its own insertion point each time it loses the input focus. Since different text controls can contain strings of differing length, we need to keep track of how far we are from each end of a given text control's string. For example, if the user last exited a given text control by using the left direction key to move to the text control above, the insertion point will be left at the leftmost end of the control that is losing the focus. If / when the user returns to the original text control, it will remember its cursor location and place the insertion point at its leftmost end. As the number of spaces to the rightmost end of the text control depends on the length of the string, we need to track the cursor position so that we know when a left key press means "move up" and when a right key press means "move down".

As an aside, the txtctl type could be used to implement cursor placement functionality for SDK 1.x applications. True BREW test case 4.1.4 (see "The Application Developer's TRUE BREW Test Guide") requires that the cursor be positioned to the right of the right-most character in a text entry field, when that field comes into focus. I'll cover such an implementation in a later article.

The Applet Data Structure
Next, we have the applet data structure for the application itself. You can see that it contains the mandatory AEEApplet as its first member. Additionally, it holds an IMenuCtl * for the soft key menu and a txtctl instance for each of the 3 text controls. Lastly, m_pActiveTxt maintains a pointer to the currently active text control. This pointer will be NULL whenever the menu control is active.


int AEEClsCreateInstance(AEECLSID ClsId, IShell *pIShell, IModule *po, 
        void ** ppObj)
{
   *ppObj = NULL;
      
   if(ClsId == AEECLSID_SCREEN)
   {
      if(AEEApplet_New(sizeof(screenapp), ClsId, pIShell,po,(IApplet**)ppObj,
         (AEEHANDLER)screen_HandleEvent,NULL) == TRUE)
      {
         if(initData((screenapp*)*ppObj))
            return (AEE_SUCCESS);
      }
   }
   return (EFAILED);
}

static boolean initData(screenapp *papp)
{
   papp->m_pMnu = NULL;
   papp->m_Txt1.m_ptxtctl = NULL;
   papp->m_Txt2.m_ptxtctl = NULL;
   papp->m_Txt3.m_ptxtctl = NULL;
   papp->m_pActiveTxt = NULL;
   papp->m_Txt1.m_spcToEnd = 0;
   papp->m_Txt2.m_spcToEnd = 0;
   papp->m_Txt3.m_spcToEnd = 0;
   return TRUE;
}

static void closeapp(screenapp *papp)
{
   ISHELL_CloseApplet(papp->a.m_pIShell, TRUE);
}

The only unusual thing about the AEEClsCreateInstance() function is the lack of a freeAppData() function in the call to AEEAppletNew(). Since no memory is allocated in the initData() function, there is nothing for a freeData() function to free. As you'll see, all the dynamic allocation takes place in the event handler's EVT_APP_START. Thus all the FREEing takes place in EVT_APP_STOP. Always use freeAppData() (or whatever name you choose to assign to the function) to release what you allocate in initAppData() and use EVT_APP_STOP to release what you allocate in EVT_APP_START.

The initData() function simply initializes all the pointer members to NULL and sets each m_spcToEnd to 0. The latter aspect captures the fact that all of the text controls will be initialized with null strings, making the cursor distance from the end of each string equal to 0.

The closeApp() function serves as a wrapper for a call to ISHELL_CloseApplet(). Why incur the overhead of an extra function call when I could simply call ISHELL_CloseApplet() directly? The only reason I like to add this extra layer is to allow for the possibility that, on shutdown, an applet may need to perform some special housecleaning tasks before exiting. By providing a closeapp() function, the shutdown operation is centralized, making it easy to accommodate any housekeeping tasks that emerge as an application evolves.


static boolean screen_HandleEvent(IApplet * pi, AEEEvent eCode, 
uint16 wParam, uint32 dwParam)
{
   screenapp *papp = (screenapp*)pi;
   switch (eCode) 
   {
      case EVT_APP_START:
      {
         AEERect r;
         int bold_h = IDISPLAY_GetFontMetrics(papp->a.m_pIDisplay, 
AEE_FONT_BOLD, NULL, NULL);
         int norm_h = IDISPLAY_GetFontMetrics(papp->a.m_pIDisplay, 
AEE_FONT_NORMAL, NULL, NULL);

         ISHELL_CreateInstance(papp->a.m_pIShell, AEECLSID_SOFTKEYCTL, 
(void**)&papp->m_pMnu);
         IMENUCTL_AddItem(papp->m_pMnu, NULL, 0, IDLI_ONE, L"Edit One", 0);
         IMENUCTL_AddItem(papp->m_pMnu, NULL, 0, IDLI_TWO, L"Edit Two", 0);
         IMENUCTL_AddItem(papp->m_pMnu, NULL, 0, IDLI_THREE, L"Edit Three", 0);
         IMENUCTL_AddItem(papp->m_pMnu, NULL, 0, IDLI_EXIT, L"Exit", 0);

         ISHELL_CreateInstance(papp->a.m_pIShell, AEECLSID_TEXTCTL,
(void**)&papp->m_Txt1.m_ptxtctl);
         r.x = TEXT_X_ORIGIN;
         r.y = VERT_SPC;
         r.dx = TEXT_X_WIDTH;
         r.dy = norm_h + FONT_PAD;
         ITEXTCTL_SetRect(papp->m_Txt1.m_ptxtctl, &r);
         ITEXTCTL_SetTitle(papp->m_Txt1.m_ptxtctl, NULL, 0, L"Title 1");
         ITEXTCTL_SetMaxSize(papp->m_Txt1.m_ptxtctl, MAX_TXT_LEN);
         ITEXTCTL_SetText(papp->m_Txt1.m_ptxtctl, L"", -1);
         ITEXTCTL_SetProperties(papp->m_Txt1.m_ptxtctl, TP_FRAME);
         ITEXTCTL_SetInputMode(papp->m_Txt1.m_ptxtctl, AEE_TM_LETTERS);
         ITEXTCTL_Redraw(papp->m_Txt1.m_ptxtctl);

         ISHELL_CreateInstance(papp->a.m_pIShell, AEECLSID_TEXTCTL, 
(void**)&papp->m_Txt2.m_ptxtctl);
         r.y += r.dy + bold_h + VERT_SPC;
         ITEXTCTL_SetRect(papp->m_Txt2.m_ptxtctl, &r);
         ITEXTCTL_SetTitle(papp->m_Txt2.m_ptxtctl, NULL, 0, L"Title 2");
         ITEXTCTL_SetMaxSize(papp->m_Txt2.m_ptxtctl, MAX_TXT_LEN);
         ITEXTCTL_SetText(papp->m_Txt2.m_ptxtctl, L"", -1);
         ITEXTCTL_SetProperties(papp->m_Txt2.m_ptxtctl, TP_FRAME);
         ITEXTCTL_SetInputMode(papp->m_Txt2.m_ptxtctl, AEE_TM_LETTERS);
         ITEXTCTL_Redraw(papp->m_Txt2.m_ptxtctl);
         
         ISHELL_CreateInstance(papp->a.m_pIShell, AEECLSID_TEXTCTL, 
(void**)&papp->m_Txt3.m_ptxtctl);
         r.y += r.dy + bold_h + VERT_SPC;
         ITEXTCTL_SetRect(papp->m_Txt3.m_ptxtctl, &r);
         ITEXTCTL_SetTitle(papp->m_Txt3.m_ptxtctl, NULL, 0, L"Title 3");
         ITEXTCTL_SetMaxSize(papp->m_Txt3.m_ptxtctl, MAX_TXT_LEN);
         ITEXTCTL_SetText(papp->m_Txt3.m_ptxtctl, L"", -1);
         ITEXTCTL_SetProperties(papp->m_Txt3.m_ptxtctl, TP_FRAME);
         ITEXTCTL_SetInputMode(papp->m_Txt3.m_ptxtctl, AEE_TM_LETTERS);
         ITEXTCTL_Redraw(papp->m_Txt3.m_ptxtctl);

         ITEXTCTL_SetActive(papp->m_Txt1.m_ptxtctl, TRUE);
         papp->m_pActiveTxt = &papp->m_Txt1;
         ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, FALSE);
         ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, FALSE);
         IMENUCTL_SetActive(papp->m_pMnu, FALSE);
         IMENUCTL_Redraw(papp->m_pMnu);

         return(TRUE);
      }

At the top of screenHandleEvent(), I obtain a screenapp pointer by casting the passed in IApplet*. At the top of EVT_APP_START, I declare a rectangle that is used to set the control rectangles for each of the 3 text controls. Note that we need not bother setting a control rectangle for the soft key menu since it appears at the bottom of the screen by default.

Next I obtain the height, in pixels, of each of the bold and normal fonts. These heights are used to set control rectangles and provide vertical, inter-control spacing. Next, the soft key instance is created and its menu items are added. Once more, the title strings should really be loaded from a resource file, but hard-coding them is of little consequence for an example such as this. The 3 text controls are then added and set up by means of various API calls (please see the API Reference for more information). Lastly, calls to ITEXTCTL_SetActive() are used to cause the input focus to apply to the first text control when the application starts up. Note that, had we passed TRUE in the call to IMENUCTL_SetActive() (instead of to the first text control), the subsequent call to IMENUCTL_Redraw() would be redundant.


  case EVT_KEY:
     switch(wParam)
     {
        case AVK_UP:
        case AVK_DOWN:  // probably unnecessary.
           IMENUCTL_HandleEvent(papp->m_pMnu, eCode, wParam, dwParam);
           if(papp->m_pActiveTxt && papp->m_pActiveTxt->m_ptxtctl)
              ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl, 
eCode, wParam, dwParam);
           break;

In this section of the event handler, we start off by processing several EVT_KEY events. You need to remember that only an active control receives events. In the case of a key event, the event handler's wParam parameter contains the virtual key code of the key that was pressed.

As it stands, the up and down keys do nothing in this application. So why include the events in the event handler? I wanted to show you that neither the menu nor the text controls do anything with AVK_UP or AVK_DOWN when the key codes are passed to the control's native event handler. Thus, as discussed earlier in this article, these two key events are available for use in the inter-control navigation scheme. The archive, available for download via a link at the end of this article, contains a version of the source file that implements this alternative.


  case AVK_LEFT:
  {
     // Move cursor to left within the current text ctl's string.  If we can't move 
     // further left, then move to the previous text ctl, unless we're already at m_Txt1,
     // in which case we do nothing.
     if(papp->m_pActiveTxt)
     {
        AECHAR *ptxt = NULL;
        uint16 len;
        ptxt = ITEXTCTL_GetTextPtr(papp->m_pActiveTxt->m_ptxtctl);
        len = WSTRLEN(ptxt);   // see Helper Functions in API Reference
        if(papp->m_pActiveTxt->m_spcToEnd < len)
        {   // cursor can move further left in string before we go to previous control
           ++papp->m_pActiveTxt->m_spcToEnd;   // increment m_spcToEnd
           // now let the text ctl actually move the cursor left
           ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl, 
eCode, wParam, dwParam);
        }
        else
        {   // move up to previous control -- can't go up from m_Txt1
           if(papp->m_pActiveTxt == &papp->m_Txt2)
           {
              ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, FALSE);
              ITEXTCTL_SetActive(papp->m_Txt1.m_ptxtctl, TRUE);
              papp->m_pActiveTxt = &papp->m_Txt1;
           }
           else if(papp->m_pActiveTxt == &papp->m_Txt3)
           {
              ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, FALSE);
              ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, TRUE);
              papp->m_pActiveTxt = &papp->m_Txt2;
           }
        }
     }
     else   // the menu has the focus...
        IMENUCTL_HandleEvent(papp->m_pMnu, eCode, wParam, dwParam);
     return TRUE;
  }
  case AVK_RIGHT:
  {
     // Move cursor to right within the current text ctl's string.  If we can't move 
     // further right, then move to the next text ctl, unless we're already at m_Txt3,
     // in which case we move the focus to the menu ctl.
     AECHAR *ptxt = NULL;
     if(papp->m_pActiveTxt)
     {
        if(papp->m_pActiveTxt->m_spcToEnd > 0)
        {   // we're not at the end of the string so move one closer
           --papp->m_pActiveTxt->m_spcToEnd;
           ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl,
eCode, wParam, dwParam);
        }
        else
        {   // move down to next control
           if(papp->m_pActiveTxt == &papp->m_Txt1)
           {
              ITEXTCTL_SetActive(papp->m_Txt1.m_ptxtctl, FALSE);
              ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, TRUE);
              papp->m_pActiveTxt = &papp->m_Txt2;
           }
           else if(papp->m_pActiveTxt == &papp->m_Txt2)
           {
              ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, FALSE);
              ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, TRUE);
              papp->m_pActiveTxt = &papp->m_Txt3;
           }
           else if(papp->m_pActiveTxt == &papp->m_Txt3)
           {
              ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, FALSE);
              IMENUCTL_SetActive(papp->m_pMnu, TRUE);
              papp->m_pActiveTxt = NULL;
           }
        }
     }
     else
        IMENUCTL_HandleEvent(papp->m_pMnu, eCode, wParam, dwParam);
     return TRUE;
  }
            

Above, still in EVT_KEY, we have the handlers for the left and right arrow keys. Since the 2 handlers are essentially mirror images, we'll limit our discussion to AVK_LEFT.

First note that, if there is no active text control, the menu must be active and IMENUCTL_HandleEvent() should therefore be given a chance to process the direction key (it will look after moving the menu selection to the left).

If m_pActiveTxt is not NULL, then the active text control's insertion point is either at the front of the string or it is not. If it's at the front of the string (i.e. m_spcToEnd == the length of the string), then we need to change m_pActiveTxt from m_Txt2 or m_Txt3 to either m_Txt1 or m_Txt2, respectively. Recall that a left key press at the start of m_Txt1 has no affect.

On the other hand, if the insertion point is not at the front of the string, we need to increment m_spcToEnd then pass the event on to ITEXTCTL_HandleEvent() so that the insertion point will move one space to the left. Note that ITEXTCTL_HandleEvent() will move the cursor, regardless of what we do with m_spcToEnd. Recall that an inactive ITextCtl instance remembers the location of its own cursor—that's just how it was built. When it becomes active again, the text control will place the cursor exactly where it was left. The m_spcToEnd parameter merely allows the application to remember this cursor location for each text control instance, from one activation to the next.

The AVK_RIGHT key functions similarly.


  case AVK_SELECT:
     if(papp->m_pActiveTxt)
        ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl, 
eCode, wParam, dwParam);
     else
        IMENUCTL_HandleEvent(papp->m_pMnu, eCode, wParam, dwParam);
     return TRUE;
        

Since command sending is not implemented for SDK 1.x text controls , ITEXTCTL_HandleEvent() does nothing in response to AVK_SELECT. Thus, only the call to IMENUCTL_HandleEvent() is necessary here. If the menu control has the focus when AVK_SELECT is pressed, it will dispatch an EVT_COMMAND event with the current menu selection ID (e.g. IDLI_ONE, #defined at the top of the program listing) contained in the event handler's wParam (more on EVT_COMMAND below).


    case AVK_CLR:
       if(papp->m_pActiveTxt) // handle backspace
          return ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl, 
eCode, wParam, dwParam);
       else
          return FALSE;   // exit app.

    default:
       if(papp->m_pActiveTxt) // handle char events
          return ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl,
eCode, wParam, dwParam);
 }
 return TRUE;

When the clear key is pressed, an active text control may respond in one of two ways, depending upon the position of the cursor. If the cursor is at the front of the text control (i.e. there are no characters on the left for the control to delete), AVK_CLR will cause the application to exit (note that this behavior was reproducible in version 2.0.0.38 of the BREW Emulator but not on a Sharp Z800 handset -- other handsets were not tested). Otherwise, the text control's native handler will cause the next character to the left of the cursor to be deleted, moving the insertion point (cursor) one space closer to the front.

Since the menu control is not interested in AVK_CLR, we simply return FALSE to the AEE which also causes the application to exit.

The default handler for EVT_KEY catches all the character events produced by the multi-tap input method and ensures that they are processed by a text control, if one is presently active. This handler causes characters to be displayed in the text control as the user presses the phone's digit keys.


  case EVT_COMMAND:

     switch(wParam)
     {
  // use evt_command to move from menu
        case IDLI_ONE:
           ITEXTCTL_SetActive(papp->m_Txt1.m_ptxtctl, TRUE);
           IMENUCTL_SetActive(papp->m_pMnu, FALSE);
           papp->m_pActiveTxt = &papp->m_Txt1;
           break;
        case IDLI_TWO:
           ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, TRUE);
           IMENUCTL_SetActive(papp->m_pMnu, FALSE);
           papp->m_pActiveTxt = &papp->m_Txt2;
           break;
        case IDLI_THREE:
           ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, TRUE);
           IMENUCTL_SetActive(papp->m_pMnu, FALSE);
           papp->m_pActiveTxt = &papp->m_Txt3;
           break;
        case IDLI_EXIT:
           closeapp(papp);
           break;
     }
     return TRUE;

When command sending is enabled for a menu control (enabled is the default) and the menu control is active, the AEE generates EVT_COMMAND events in response to the user pressing AVK_SELECT. With the EVT_COMMAND event, the wParam passed in to the event handler contains the item ID for the current menu selection. Thus, the EVT_COMMAND handler above provides the user with the ability to move the focus from the menu control to any of the text controls by simply selecting the menu item corresponding to the desired text control. Note that command sending can be controlled through the IMENUCTL_EnableCommand() API function; please see the API Reference for details.

If command sending were implemented for ITextCtl's in SDK 1.x (it is implemented in SDK 2.0), we could simply give each text control its own unique ID. This ID would be sent to the application's EVT_COMMAND handler (in the wParam parameter) every time the user pressed AVK_SELECT inside an active text control. Thus each text control could simply identify itself, permitting the programmer to implement control-specific functionality for each ITextCtl without having to maintain a pointer to the one that is currently active.


  case EVT_APP_STOP:
     IMENUCTL_Release(papp->m_pMnu);
     papp->m_pMnu = NULL;
     ITEXTCTL_Release(papp->m_Txt1.m_ptxtctl);
     papp->m_Txt1.m_ptxtctl = NULL;
     ITEXTCTL_Release(papp->m_Txt2.m_ptxtctl);
     papp->m_Txt2.m_ptxtctl = NULL;
     ITEXTCTL_Release(papp->m_Txt3.m_ptxtctl);
     papp->m_Txt3.m_ptxtctl = NULL;
     papp->m_pActiveTxt = NULL;
     return TRUE;
  default:
     break;
}
return FALSE;
}

Finally, this brings us to EVT_APP_STOP where the dynamically allocated resources are released, in preparation for the application to exit.

Download project files: screensource.zip (5 KB).

Originally published in the BREW Wireless Resource Center



   
Murray Bonner is President of Golden Creek Software Inc., a BREW software developer and a provider of custom training and software development services. Murray has been working with the BREW SDK for nearly 2 years and writes to share his BREW development experience, gained mostly at the expense of his hairline. He welcomes your .
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date