Home > Palm > Tutorial > UI
 
  Palm Tutorial
UI

Palm Tutorial

 Objective

To design and develop user interface with more advanced objects such as sliders, progress bar, multiple depth bitmaps...

 Concepts

Using more sophisticated UI objects

So far, we've only dealt with graphical objects like buttons, labels, fields, popup lists... At some point, you will need to add more complex behaviour and user interaction to your application. Palm OS docs are pretty well structured and contain all the information you need to do so. However, all this information is spread over dozens of pages. This topic of our tutorial will provide you with a "concentrate" of how to develop cool UIs.

Using several forms in the same app

Also, we've only addressed apps that have one main form. Here, you'll see how to create, load, activate and switch several forms within your application.

Graphical objects

Here's the overview of those new guys we're going to study:

  • FONT: create your own font into a .txt file and use it to display text on the UI
  • FORMBITMAP: how to deal with grayscale and color images of different depths
  • SELECTORTRIGGER: allows you to tap on a trigger that will pop up a form (like in the DateBook when you pick an hour)
  • STRINGTABLE: define a collection of strings into the .prc and load it in your app (You're a smart developer... You don't like hard-wired text, do you?)
  • GRAFFITISTATEINDICATOR: this is what shows the user when s/he taps a dot or a backslash in the graffiti area, which allows the user to enter special characters (tap a dot, you'll see a big dot appearing on the screen, and then tap a space, you'll get a dash and the dot disappears - this dot was a graffiti state indicator)
  • SCROLLBAR: create a scrollbar and react to the user's tap on the scroll arrows
  • SLIDER: this one looks like a cursor that you slide along a line, just like you do when you raise or lower the volume on a sound mixer. Use it in your app to adjust a value graphically.
  • PROGRESS BAR: use one when your app opens up a remote connection or fires any task that takes enough time to make the user angry if there's no feedback...
  • GADGET: that's the magical object. Basically, it's a rectangular area that you declare as such, and for which you define and manage the behaviour.
And there's a short list of new clauses that PilRC uses to compile our .rcp:

  • ICONFAMILY: Palm launcher extracts an ICON resource from each .prc and displays them. You'll then tap the icon associated to the app you want to run. If you develop a commercial-grade app, you should take into account that some of your users have a monochrom display, others have grayscale, others have 256 colors. If you only create a monochrom ICON, users who have a cool color display will be a bit unhappy. If you only create a color ICON, users having a monochrom device will just get a "black-and-whited" version that will likely not look very nice. And so forth concerning grayscale. So, you'll need to create 4 versions of your icon: monochrom, 4-grayscale, 16-grayscale and 256-color.
  • SMALLICONFAMILY: in Palm launcher, you can set preferences to view apps by LIST versus ICON. This displays a SMALLICON rather than an ICON, and allows to fit more apps on the display. Just like ICONFAMILY above, this clause allows you to embed a small icon for each possible color depth.
  • VERSION: defines the version of your app
  • LAUNCHERCATEGORY: with this clause, you can tell hotsync in what category it should install your app (System, Main, Games...). If the category doesn't exist, it'll be created automagically. Please note that all the apps of our tutorial will be installed in category 'Tutorial' (logical - huh?!?)

 Exercise

Download the ZIP file.

In ui.h:

  • define constants for the selector: SelectorDay, SelectorTime, SelectorStartEnd
  • define three string tables:
    #define StringTableArdipithecusStr 1403
    #define StringTableAustralopithecusStr 1404
    #define StringTableHomoStr 1405
  • define three objects for our scroll bar: ScrollField, ScrollBar, ScrollStr
  • define some values for the slider: SliderSlider=1701, SliderThumb=1702, SliderBackground=1703, SliderMax=40
  • add the dimensions of the gadget:
    #define GadgetWidth 40
    #define GadgetHeight 40
  • define a Font and FontID for the reverse and smiley fonts the same way the FunFont was defined

In ui.rcp:

  • add reverse and smiley fonts
  • add BITMAPGREY16...
  • add BITMAPFAMILY... for the slider's thumb
  • add StringTableAustralopithecusStr with values "A. " "anamensis -4.2M" "afarensis -3.9M" "africanus -3.2M" "boisei -2.1M" "robustus -2M"
  • in FontForm, add FONT SmileyFontID where appropriate
  • in BitmapForm, add Grey16Bitmap and Color256Bitmap where they should appear
  • in SelectorForm, add a selector for time
  • in GraffitiForm, place a GRAFFITISTATEINDICATOR at... the right place :)
  • in ScrollForm, insert a SCROLLBAR whose ID is ScrollBar, position is (previous_right+7 previous_top 7 previous_height), value and min are 0, max is 7 and pagesize equals 1
  • in SliderForm, add a beautiful slider like this:
    SLIDER ID SliderSlider AT (10 PREVBOTTOM+4 140 30) FEEDBACK THUMBID SliderThumb BACKGROUNDID SliderBackground VALUE 0 MIN 0 MAX SliderMax PAGESIZE 1
  • in GadgetForm, create a GADGET with GadgetGadget as an ID, x=CENTER, y=90, width=GadgetWidth, height=GadgetHeight). And oh yes! It should be USABLE.

In ui.c:

  • declare 3 font handles: MemHandle funFontH, reverseFontH, smileyFontH;
  • declare a pointer to our progress indicator: ProgressPtr prg = NULL;
  • in BitmapFormHandleEvent() add this code to display 16K-color bitmaps only if OS version >= 4:
    FormPtr frm = FrmGetActiveForm();
    UInt16 obj = FrmGetObjectIndex(frm, Color16KBitmap);
    FrmRemoveObject(&frm, obj);
    frm = FrmGetActiveForm(); // refresh pointer that may have changed after FrmRemoveObject
    FrmNewLabel(&frm, Color16KBitmap, "Need OS4+", 110, 115, 0);
  • in SelectorFormHandleEvent()/case SelectorTime, add this to assign a default time:
    DateTimeType dt;
    TimSecondsToDateTime(TimGetSeconds(), &dt); //get today date
    hour = dt.hour;
    minute = dt.minute;
  • and that to get what time the user selected:
    char str[40];
    TimeToAscii(hour, minute, PrefGetPreference(prefTimeFormat), str);
    SetSelector(SelectorForm, SelectorTime, str);
  • in DisplayStringTable(), add this two-pass chunk to load the strings from the table:
    for (count = 0; true; count++)        // pass 1: let's count # of strings
        if (StrLen(SysStringByIndex(strTbl, count, str, sizeof(str))) <= 3) // only got prefix?
           break; // exit loop
    for (i = 0; i < count; i++)           // pass 2: letz get'em stringz!
    {
      SysStringByIndex(strTbl, i, str, sizeof(str));
      WinDrawChars(str, StrLen(str), 10, (64 - 10 + ((i+1)*(96 / (count+1)))));
    }
  • in ScrollFormHandleEvent(), draw a rectangle around the table, to make it look nicer:
    WinDrawGrayRectangleFrame(simpleFrame, &rectField);
    WinDrawGrayRectangleFrame(simpleFrame, &rectBar);
  • upon receiving a sclRepeatEvent, do this:
    UInt16 newValue = event->data.sclRepeat.newValue;
    FormPtr frm = FrmGetActiveForm();
    FieldPtr fld = (FieldPtr)FrmGetObjectPtr(frm, FrmGetObjectIndex(frm, ScrollField));
    static UInt16 curValue = 0;
    if (newValue > curValue)
       FldScrollField(fld, newValue-curValue, winDown);
       else FldScrollField(fld, curValue-newValue, winUp);
    curValue = newValue;
  • in SliderFormHandleEvent(), upon ctlRepeatEvent, you need to refresh the shape of our figure:
    UInt16 newValue = event->data.ctlRepeat.value;
    if (newValue != curValue)
    {
      DrawShape(curValue, newValue);
      curValue = newValue;
    }
  • in ProgressCallback(), make sure you copy "Finishing" as a string (refer to "case 0")
  • in ProgressFormHandleEvent()/case ProgressSlow, start progress dialog for slow process:
    count = 0;
    max = 0x0012;
    StrCopy(fileSize, "huge");
    if ((prg = PrgStartDialog("Slow Task", &ProgressCallback, (void*)fileSize)) == NULL)
       FrmCustomAlert(ErrorAlert, "Unable to start progress dialog", "", "");
  • in DrawGadget() here's the code that reverse from down to up:
    IndexedColorType textColor = WinSetTextColor(UIColorGetTableEntryIndex(UIFormFrame));
    IndexedColorType backColor = WinSetBackColor(UIColorGetTableEntryIndex(UIFormFill));
    WinDrawChars("Empty :(", 8, rect->topLeft.x+2, rect->topLeft.y+rect->extent.y-14);
    WinSetTextColor(textColor);
    WinSetTextColor(backColor);
    up = !up;
  • in AppHandleEvent(), you need to add some code in the case of nilEvent. Stop the progress dialog:
    PrgStopDialog(prg, false);
    prg = NULL;
  • or update it:
    PrgUpdateDialog(prg, 0, stage, dots, true);
  • in AppStart(), get a handle on our home-made "smiley" font
Make the app and test it!

 Solution

Here's the ZIP file.

And here's how the app should like:

Palm Tutorial Palm Tutorial Palm Tutorial Palm Tutorial
Palm Tutorial Palm Tutorial Palm Tutorial Palm Tutorial
Palm Tutorial Palm Tutorial

Next topic

 
[ Copyright © 2000- Eric Poncet - All rights reserved ]

[ Stage de musique classique | Stage de musique baroque | Stage de musique de chambre | Stage de musique latine ]
[ Stage de jazz | Stage de musiques actuelles | Stage de funk | Stage de metal | Stage de pop | Stage de reggae | Stage de rock ]
[ Stage d'improvisation | Colonie musicale ]