Share via


ODLIB (Windows Embedded CE 6.0)

1/5/2010

The Networked Media Device Sample Application uses a user interface library called the Owner-Draw Library (ODLIB). This library is provided as an example only, and it may contain untested functionality. If you choose to use portions of this library, you should test it fully to be sure that it functions as you expect in your environment.

ODLIB Classes

  • CSetupApp
    Provides the base class for ODLIB's main class. It does the following:

    • Initializes the EBU Engine.
    • Checks for a previous setup instance.
    • Checks for applications that are already running.
    • Manages window registration.
    • Maintains the main message loop.
    • Starts the engine thread.
    • Maintains the application's global application variables such as busy state.
    • Is responsible for creating the following global objects:
      • Border window (CBorderWnd).
      • Page manager (CPageManager).
      • Font manager (CFontManager).
      • The Heartbeat thread.
  • CBorderWnd
    Creates a window that acts as a parent window for all other elements in the application.

    Processing all general application messages is done in the CBorderWnd::WndProc method. Messages that are not handled there are passed to CPageManager for processing. If CPageManager does not process the message, it is then passed to the DefWindowProc object.

    This window may have a background fill color or fill bitmap. If neither of these is used, the window automatically sizes itself to the current front page and remains hidden behind that page.

  • CPageManager
    Maintains an array of available pages (subclassed from the CAnimPage class) with their creation callbacks.

    In addition to maintaining an array of available pages, this class also does the following:

    • Creates pages on demand as the back page.
    • Creates the message and alert pages on startup for ready use.
    • Controls the transition of a page to be shown from back page to front page.
    • Handles page transitions and display messages (these start with WMU_AM_). Any messages it receives that are not processed are passed to the current front page (if any).
  • CFontManager
    The font manager is responsible for maintaining the internal cache of font objects.

    On startup, the font manager loads the default fonts (STR_FONT_BUTTON, STR_FONT_DEFAULT, STR_FONT_LARGE, STR_FONT_SMALL, STR_FONT_BOLD) from the application string table.

    When fonts are requested at runtime, the font cache is checked to see if it is already loaded. If not, the font is created and stored in the cache.

    The font manager allows per-string font specifications. A font specification is in the format: [font name, font height, font weight]. For example, [Segoe Light, 30, 700].

    Any string can have a font specifier at the beginning of the string, as shown in the following code example.

    "[Segoe Light, 30, 700]A large bold text string"

    "[Segoe Light, 10, 500]A small text string"

    ODLIB defines a set of default fonts in the %_WINCEROOT%\public\fp_nmd\oak\ownerdrawnUIlib\odlib.rc resource file, as shown in the following code example.

    ALS_FONT_BUTTON "[Segoe Light,30,700]" // default for buttons, Alias [BN]

    ALS_FONT_DEFAULT "[Segoe Light,15,700]" // default text font, Alias [DF]

    ALS_FONT_BOLD "[Segoe Light,19,700]" // Alias [BF]

    ALS_FONT_LARGE "[Segoe Light,30,700]" // Alias [LF]

    ALS_FONT_SMALL "[Segoe Light,12,400]" // Alias [SF]

    Buttons always use the ALS_FONT_BUTTON specification if no other font is specified. All other text uses the ALS_FONT_DEFAULT specification if no other font is specified.

    The following default fonts can be used by alias in strings: "[BN]String using button default font" and "[LF]String using large default font".

    There is also one additional alias that is used to access the system font "[SY]": "[SY]A string using the system default font".

    Font allocation and tracking is automatically handled in the font manager.

    If a string does not fit where you want it (for example, if a button message is too large for the button), you can modify the font by adding a custom font specifier to the beginning of the string, as shown in the following code example.

    "[Segoe Light, 25, 700]Button String"

    This custom font specifier forces the font to be rendered at 25 pixels instead of the default of 30 pixels. Rendering at 25 pixels allows more text to fit into the button. This is useful during the localization of a product (for example, if a localized string does not fit, it can have a custom font added to it, and no code changes are required).

  • Heartbeat thread
    Uses the WaitForSingleObject method to act as a low system impact delay. This delay can be defined by the application.

    When WaitForSingleObject times out, a WMU_PULSE event is sent to the main message loop. This WMU_PULSE event is then passed down to all animlib objects to allow them to process animations and page changes in a coordinated manner.

    The m_hHeartBeatEvent event is sent by the CSetupApp class to notify the heartbeat that it is time to shutdown.

Interface Classes

  • CSetupApp
    This is the base class for the setup application's main class.

    Developers subclass from this class for the main setup UI functionality.

  • CPageBase
    Developers subclass from this class for all UI pages. These classes are roughly analogous with dialog templates. This class is based around a child window of the border window.

Message Flow

Messages flow through the application in the following manner depending on the source of the message.

  • CSetupApp::Main
    The main message loop.
  • CBorderWnd::ProcessMessage
    The main message handler.
  • CPageManager::ProcessMessage
    Window-specific messages start in the same pipeline as general messages and then filter down from there.

    Control-specific messages (such as button and text) either start at the CAnimPage (or derived page) level or the control itself.

  • CAnimPage::ProcessMessage
    Window-specific messages start in the same pipeline as general messages and then filter down from there.

    Control-specific messages (such as button and text) either start at the CAnimPage (or derived page) level or the control itself.

  • Derived page ::ProcessMessage
    Window-specific messages start in the same pipeline as general messages and then filter down from there.

    Control-specific messages (such as button and text) either start at the CAnimPage (or derived page) level or the control itself.

Pulse Flow

The WMU_PULSE messages that the Heartbeat thread generates filter through the application as follows:

  1. CBorderWnd::ProcessMessage
  2. CPageManager->Pulse
  3. The front page (if any)
  4. If the page if visible, ScreenItemList::Pulse
  5. For each control in the screen item list, CScreenItem::Pulse
  6. The message page (if any)
  7. If the page if visible, ScreenItemList::Pulse
  8. For each control in the screen item list, CScreenItem::Pulse

Configuring a Graphical Busy Message

You can declare a callback that takes a CAppMessage object as a parameter and returns a BOOL as shown in the following code example.

BOOL CMyApp::MessageInitCallback(CAppMessage *pAppMessage)
{
   // Static method used as a callback for initalizing the 
   // application alert

   // Set the background image (required)
   pAppMessage->SetBackground(IDB_Sprite_MessageBox);

   SHADOW_TEXT_CREATION
      TextParams;
   
   // Page heading (required)
   TextParams.m_ScreenRect = CRect(10, 10, 160, 160);
   TextParams.m_pszText   = "";
   pAppMessage->SetTitleText(pAppMessage->AddControl(TextParams));

   // Message (required)
   TextParams.m_ScreenRect = CRect(360, 10, 550, 160);
   TextParams.m_pszText   = "";
   pAppMessage->SetBodyText(pAppMessage->AddControl(TextParams));

   // Add a sprite of the icon
   PHASED_SPRITE_CREATION
      SpriteCreation;
   SpriteCreation.m_uiResID      = IDB_Sprite_MainAnim;
   SpriteCreation.m_Position      = CPoint(170, 10);
   SpriteCreation.m_uiNumFrames   = 8;

   // Add the sprite
   pAppMessage->AddControl(SpriteCreation);

   return TRUE;
}

In this callback, you should call the CAppMessage::SetMessageInitCallback method with the callback address.

At a minimum, you must set the background for the message in this callback and create a CScreenText object for the title and body of the message. These objects are then assigned to the appropriate internal structures by using the SetTitleText and SetTextBody methods of the CAppMessage pointer.

This callback is called when the SetMessageInitCallback method is processed.

You may create any other read-only screen items that you want in this callback.

This busy message will be used when you make a call to the SetBusy method. The title text is set to the setup application title, and the body is set to the passed-in message.

Configuring a Graphical MesageBox

You can declare a callback that returns a BOOL and accepts a CAppAlert pointer, as shown in the following code example.

BOOL CMyApp::AlertInitCallback(CAppAlert *pAppAlert)
{
   // Static method used as a callback for initalizing the 
   // application alert

   // Set the background image (required)
   pAppAlert->SetBackground(IDB_Sprite_AlertBox);

   SHADOW_TEXT_CREATION
      TextParams;
   
   // Page heading (required)
   TextParams.m_ScreenRect = CRect(10, 10, 160, 160);
   TextParams.m_pszText   = "[BF]";
   pAppAlert->SetTitleText(pAppAlert->AddControl(TextParams));

   // Message (required)
   TextParams.m_ScreenRect = CRect(360, 10, 550, 160);
   TextParams.m_pszText   = "";
   pAppAlert->SetBodyText(pAppAlert->AddControl(TextParams));

   // Add the three potential buttons (these are required)
   
   BUTTON_CREATION
      ButtonParams;

   ButtonParams.m_uiButtonSndID   = IDW_Button;
   ButtonParams.ButtonTextInfo.m_uiFormat         
= DT_VCENTER | DT_CENTER | DT_SINGLELINE;
   ButtonParams.m_dwStyle         = WS_GROUP;   // First button must be group
   ButtonParams.m_ptBtnPos.y      = 193;
   ButtonParams.m_uiBmpID         = IDB_Button_1;
   ButtonParams.ButtonTextInfo.m_pszText = "";
   ButtonParams.m_hwndMessageDest   = pAppAlert->GetPageWnd();
   ButtonParams.m_bManualShow      = TRUE;

   // Left button
   ButtonParams.m_pszTestingTitle   = "Left";
   ButtonParams.m_ptBtnPos.x      = 11;
   ButtonParams.m_wMessage         = WMU_PAGE_BUTTON_LEFT;
   pAppAlert->SetLeftButton(pAppAlert->AddControl(ButtonParams));
   ButtonParams.m_dwStyle = 0; // Shut of the WS_GROUP bit

   // Center button
   ButtonParams.m_pszTestingTitle   = "Center";
   ButtonParams.m_ptBtnPos.x      = 194;
   ButtonParams.m_wMessage         = WMU_PAGE_BUTTON_CENTER;
   pAppAlert->SetCenterButton(pAppAlert->AddControl(ButtonParams));

   // Right button
   ButtonParams.m_pszTestingTitle   = "Right";
   ButtonParams.m_ptBtnPos.x      = 376;
   ButtonParams.m_wMessage         = WMU_PAGE_BUTTON_RIGHT;
   pAppAlert->SetRightButton(pAppAlert->AddControl(ButtonParams));

   // Add a sprite of the icon
   PHASED_SPRITE_CREATION
      SpriteCreation;
   SpriteCreation.m_uiResID      = IDB_Sprite_MainAnim;
   SpriteCreation.m_Position      = CPoint(170, 10);
   SpriteCreation.m_uiNumFrames   = 8;

   // Add the sprite
   pAppAlert->AddControl(SpriteCreation);

   return TRUE;
}

This callback will be called when the alert is being constructed for use. Because it is a modal dialog, it will be created and destroyed during each use.

Required Controls

The following table shows the required controls.

Control Assignment

CScreenText: Title for alert.

Use SetTitleText to assign it.

CScreenText: Body for alert.

Use SetTextBody to assign it.

CButton: Potential left button.

Use SetLeftButton to assign it.

CButton: Potential center button.

Use SetCenterButton to assign it.

CButton: Potential right button.

Use SetRightButton to assign it.

You may create any other read-only screen items that you want in this callback.

To use the message box call, use the following code example.

int Alert( HWND hwndParent, UINT uType, UINT uMessage, ... );

Six-State Button Behavior

The following sections describe the states used for animated buttons.

Note

Be sure that your artists are aware of the rollover state. When a mouse pointer is on top of a button, this third state is drawn. When you move the pointer off of the button, the button immediately returns to its previous state.

Ee480306.collapse(en-US,WinEmbedded.60).gifStates

The following are the states for six-state button behavior:

  1. Inactive
  2. Active (up)
  3. Rollover (pointer is over it)
  4. Active (depressed)
  5. Default(without keyboard focus)
  6. Default(with keyboard focus)

Note State 5 (the default without keyboard focus) means that if a carriage return is hit, the button displaying state 5 is the button to process the carriage return.

This can cause problems if some other control has the keyboard focus. An example of this situation is when you have an edit box on the screen. You can be typing in the edit box while one of the buttons is displaying state 5. At this point in time, if you were to bump your mouse and rollover any button, that button would display state 3, the rollover state. Because your edit box would still have the keyboard focus, all keystrokes, with the exception of the carriage return, would go to the edit box. Moving the mouse pointer off of the button, without clicking, would cause the button to redraw as state 5.

Seven-State (Animated) Button Behavior

Each of the seven states of this button is represented by a bitmap. The first six states correspond to the same states as the six-state button behavior. The seventh state is only necessary for those buttons that should do a post-button-up animation. If you want to have a button animate after it is clicked (button-down and button-up), you need a seventh state, and hence a seventh bitmap. You might also note that all states do not necessarily need to have the same number of frames. This way, it is possible to have only one state animate.

Ee480306.collapse(en-US,WinEmbedded.60).gifStates

The following are the states for seven-state button behavior:

  1. Inactive
  2. Active
  3. Rolled-over
  4. Depressed
  5. Default
  6. Default with focus
  7. Post-click

Check Box and Radio Button Behaviors

As mentioned in the six-state button behavior section, moving the mouse pointer over a button causes the button to draw differently. For check boxes and radio buttons, the two rolled-over states should be added to the bottom of their corresponding bitmaps.

Ee480306.collapse(en-US,WinEmbedded.60).gifStates

The following are the states for check box and radio button behaviors:

  1. Inactive (clear)
  2. Inactive (checked)
  3. Active (clear)
  4. Active (checked)
  5. (has keyboard) Focus (clear)
  6. (has keyboard) Focus (checked)
  7. Depressed (clear)
  8. Depressed (checked)
  9. (mouse) Rolled-over (clear)
  10. (mouse) Rolled-over (checked)

See Also

Concepts

Networked Media Device Sample Application

Other Resources

Networked Media Device Architecture