Developing a \"Skin-Enabled\" Application

 

User interface design can be extremely difficult, and even if you come up with a design that is very popular, you can count on someone complaining about it. This article shows you how to create a user interface based on user-definable skins, so your users can choose for themselves what they like.

Applies to:
   Microsoft Windows Powered Pocket PC 2000
   A live network connection from your Pocket PC
   Microsoft eMbedded Visual C++ version 3.0
   VOImage class

Languages Supported

English

Creating the Skin Files

A "skin" is a collection of graphics files plus a text file, read by your application, which describes where various graphics should be placed on the user interface (UI). With the advent of landscape mode on the Pocket PC, there are currently two resolutions you should absolutely support: 240 x 320, also known as "portrait" or "standard" resolution, and 320 x 240, also known as "landscape" resolution. In this article, we use a simple calculator as our application model. The graphics described in the following steps are available for download at the Virtual Office Systems Web site.

Sample control list.

To create a skin for the calculator sample application:

  1. List the types of objects your application will present to the user - including buttons, tabs, lists of items, and so on. For best results, I recommend sketching the interface and labeling the components, as shown in Figure 1.

  2. Use Paint or another paint program (I use JASC Paintshop Pro) to create two graphics files. Make one 240 x 320 pixels and the other 320 x 240 pixels. Save them as PNG, GIF, or BMP files (depending on your paint program capabilities). These will serve as your background images.

  3. Create a graphic that is 200 x 32 pixels. Make it a light-green rectangle to keep it simple. If you want to support landscape, make another similar display area that is 280 x 32 pixels.

  4. Create graphics for the other items in the list. For this example, make all the buttons 32 x 32 pixels, except for the PLUS SIGN, which should be 32 x 78 pixels.

  5. Create a text file named "Sample.Calculator.skin" that contains the following (if your filenames are different, make the appropriate changes):

    [Head]
    SkinName=Sample Calculator Skin
    Author=Adam J. Tratt
    Description=Sample skin for calculator application
    
    [Graphics]
    Background=SampleCalc.gif
    Background.320x240=SampleCalcLS.gif
    Display=Display.gif
    Display.320x240=DisplayLS.gif
    Button0=0.gif
    Button1=1.gif
    Button2=2.gif
    Button3=3.gif
    Button4=4.gif
    Button5=5.gif
    Button6=6.gif
    Button7=7.gif
    Button8=8.gif
    Button9=9.gif
    ButtonPlus=Plus.gif
    ButtonMinus=Minus.gif
    ButtonTimes=Times.gif
    ButtonDivide=Divide.gif
    ButtonDecimal=Decimal.gif
    ButtinEqual=Equals.gif
    ButtonClear=Clear.gif
    
    // Areas are bounding rectangles x1,y1,x2,y2
    [Areas]
    CalculatorDisplay=38,14,238,46
    CalculatorDisplay.320x240=38,14,318,46
    Button0=60,198,92,230
    Button1=60,152,92,184
    Button2=106,152,138,184
    Button3=152,152,184,184
    Button4=60,106,92,138
    Button5=106,106,138,138
    .       Button6=152,106,184,138
    Button7=60,60,92,92
    Button8=106,60,138,92
    Button9=152,60,184,92
    ButtonPlus=152,198,230,230
    ButtonMinus=198,106,230,138
    ButtonTimes=14,106,46,138
    ButtonDivide=14,152,46,184
    ButtonDecimal=106,198,138,230
    ButtonEqual=152,198,184,230
    ButtonClear=2,14,34,46
    [Fonts]
    CalculatorDisplay=Tahoma,10
    
    [Colors]
    CalculatorDisplay=0,0,0
    

Note that in the "Areas" section, the buttons are at the same location in any resolution. In some of the values, you will notice that there are different coordinates for 240 x 320 than for 320 x 240. Our application must first look for a setting that is specific to the current resolution; if that value isn't found, the resolution is not specified. Using this method ensures that no matter what resolution your users are running, they will always get some sort of a display, but the skin creators can optimize the skins for specific resolutions.

Reading the Skin Files and Displaying the User Interface

You should provide at least one skin with any application; make sure that you give your users a menu selection or another method of selecting which skin they want to use! While it is beyond the scope of this article to walk you through every step involved in creating a complete UI, here are the main steps involved in reading the skin and displaying it to the user:

  1. Open the currently selected .SKIN file (see File I/O in a C++ Application on the Pocket PC for more information on reading files).
  2. In the processing of the WM_PAINT message, check to see if the graphics for the current skin have been loaded. If they haven't, load them now.
  3. Also in the WM_PAINT message, display any graphics at the coordinates listed in the "Areas" section of the file. For text areas, as with our "CalculatorDisplay" area, display the contents in the specified font and size within the coordinates listed in the "Areas" section.
  4. Process skin selection changes and ensure that if the user changes the skin, any loaded graphics, fonts, and other elements from previous skins are deleted from memory so that the new skin will be displayed correctly.

Processing Input Events (User Clicks) on the Skin

The ease of reacting to user clicks is probably the easiest and most impressive part of using skins. To process user clicks in a skin-based application:

  1. In the processing of the WM_LBUTTONUP message, check the area coordinates from the .SKIN file and translate the click into a function call for the button pressed. Sometimes (as is the case in the calculator example with the number buttons) it makes sense to call the same function with a different parameter, so in our example we might have a function called OnNumberPress(int nNumber).
  2. For list boxes, you will generally either restrict the list to a particular region of the screen and use a standard list box or, more commonly, use a paging method (display as many items as will fit in the specified region and offer a next and previous page graphic).
  3. Depending on the application, you may want to support tap-and-hold functions for certain controls as well. In the calculator, for example, you might want to support cut-and-paste operations on the calculator display area. You can tell which control is being affected the same way you do with the WM_LBUTTONUP processing.

Conclusion

By allowing your users to choose an interface that is completely external to your application, you not only give them the ability to choose their own look and feel, you give your application a fresh new look—without writing a single additional line of code. Pocket PC users in particular are accustomed to colorful, expressive interfaces and above all, they are used to having choices ranging from the way they input text to their Today screen display. The day may soon come when single-interface applications are left behind...