wiki:Docs/825gen2/Dev/UpdatingLegacyAppsToNewLook

Updating Legacy Apps to New Look

Consider if the app to be changed only has minor changes from one of the standard apps. In this case it may be easier to use the code from the new style standard app and merge the changes into it.

Otherwise, follow the below steps.

  1. If it has not been done yet create 825gen2 build configurations for the project: Debug-ARM825, Release-ARM825, (See Updating Legacy Apps) and Debug-ARM825-SIM (See Simulating 825gen2 Apps).
  1. Copy the files apphelpers.cpp, apphelpers.h, and appinfo.h from one of the new standard projects such as ID storage into the project to update. Changes to these files might be needed. For example, if different fonts or font sizes are desired these are specified in apphelpers.cpp.
  1. Create a new header file wght_screen.h in the src folder. Copy the following code into the header. This is a starting point and the CFormRect variables defined are common for many projects. It may be necessary to add additional CFormRects for the project being updated.
/*
 * wght_screen.h
 *
 *
 */

#ifndef SRC_WGHT_SCREEN_H_
#define SRC_WGHT_SCREEN_H_

#define NUM_WT_INDEXES  3 // Gross, tare, net
#define WT_INDEX_GROSS  0
#define WT_INDEX_TARE   1
#define WT_INDEX_NET    2

class CWeighingScreen
{
#if ARM64
    CFormRect rectWtLbl_[NUM_WT_INDEXES]; // Location for gross, tare, net labels
    CFormRect rectWt_[NUM_WT_INDEXES];
    CFormRect rectWtUnits_[NUM_WT_INDEXES];
    CFormRect rectWtStatus_;
    CFormRect rectCapacity_[2]; // If OIML needs two lines
    CFormRect rectErrorMsg_;
    CFormRect rectLargeMsg_; // Size of all weight rects, used for "WEIGHT ERROR", or "OVER CAPACITY"
    CFormRect rectManTare_;
    CFormRect rectBelowButtons_;
    CFormRect rectWeightBackground_;
    CFormRect rectOperator_;
    CFormRect rectDateTime_;
#endif

    CSecondTimer timerErrMsg_;

public:
   CWeighingScreen(void)
   {

   }

#if ARM64
    void SetupDisplayLocations(void);
#endif

};
  1. Create a source file wght_screen.cpp in the src folder. Copy the following code into this file:
#include "cardinal825.h"
#include "appinfo.h"
#include "apphelpers.h"
#include "langstr.h" // Include if using lib825lang
#include "wght_screen.h"

extern int curScale;
extern CLangStr lang; // Include if using lib825lang
// It will likely be necessary to add other extern vars

#if ARM64

void CWeighingScreen::SetupDisplayLocations(void)
{
        int n;

        CFormRect rect;
        CFormAdvanceY advanceY;

        // Weight status below capacity with is fontIndexSmallPrompt,multiplier 1.0 plus fixed DrawBorder  height FONT_HEIGHT + 16
        rect.SetTopBasedOnFont(formFontSet.GetFont(fontIndexSmallPrompt), 1.0, BORDER_BOX_HEIGHT);
        rect.SetHeightBasedOnFont(formFontSet.GetFont(fontIndexSmallPrompt), 1.0);
        rect.SetLeftAndWidthBasedOnDspArea(&dspMain, 0.26, 0.25); // Show above of gross weight value

        rectWtStatus_ = rect;
        rectWtStatus_.SetLeftAndWidthBasedOnDspArea(&dspMain, 0.0, 0.30);
        rectWtStatus_.SetTopBasedOnFont(formFontSet.GetFont(fontIndexSmallPrompt), 1.7, BORDER_BOX_HEIGHT);

        for(n = 0; n < 2; n++) {
                if(n == 0) {
                        rectCapacity_[n].SetY(BORDER_BOX_HEIGHT);
                } else {
                        rectCapacity_[n].SetTopBasedOnFont(formFontSet.GetFont(fontIndexSmallPrompt), BORDER_BOX_HEIGHT);
                }
                rectCapacity_[n].SetX(0);
                rectCapacity_[n].SetLeftAndWidthBasedOnDspArea(&dspMain, 0.01, 0.41);
                rectCapacity_[n].SetHeightBasedOnFont(formFontSet.GetFont(fontIndexSmallPrompt), 1.0);
        }

        advanceY.SetBasedOnFont(formFontSet.GetFont(fontIndexSmallPrompt), 1.0, 0);

        rect += advanceY;

        rectManTare_ = rect;
        rectManTare_.SetLeftAndWidthBasedOnDspArea(&dspMain, 0.31, 0.20);
        rectManTare_.SetTopBasedOnFont(formFontSet.GetFont(fontIndexSmallPrompt), 1.7, BORDER_BOX_HEIGHT);

        // Setup weight label, value, and units locations
        // horizontal coordinates based on display area width
        // vertical coordinates based on font heights
        //
        //  Header
        // Capacity 1
        // Capacity 2
        //
        //   |- 0% 25% -|- 26% - 51%  -|- 55% 70% -|
        //
        //                wt status
        //    Gross          120000       lb
        //
        //    Tare            40000       lb
        //
        //    Net             80000       lb
        //
        //   Error message
        //   ----- Buttons -------

        rect.SetHeightBasedOnFont(fontBigLabel, 1.0);
        // move Y position down to 1/4 of font height.
        int heightNZ = fontBigLabel.GetFont(0).GetHeight();
        heightNZ = heightNZ / 2;
        int heightZ = fontBigLabel.GetFont(1).GetHeight();
        heightZ = heightZ / 2;
        advanceY.SetBasedOnFont(fontBigLabel, 1.0);
        rect.GetRect(0).SetY(rect.GetRect(0).GetY() + heightNZ);
        rect.GetRect(1).SetY(rect.GetRect(1).GetY() + heightZ);

        for(n = 0; n < NUM_WT_INDEXES; n++) {
                rect.SetLeftAndWidthBasedOnDspArea(&dspMain, 0.01, 0.24);
                rectWtLbl_[n] = rect;

                rect.SetLeftAndWidthBasedOnDspArea(&dspMain, 0.26, 0.25);
                rectWt_[n] = rect;

                rect.SetLeftAndWidthBasedOnDspArea(&dspMain, 0.55, 0.15);
                rectWtUnits_[n] = rect;

                rect += advanceY;
        }

        // Large message such as "WEIGHT ERROR" upper left is set same as weight label "Gross", lower right is same as net weight units label.
        rectLargeMsg_.SetLocationAndSizeFrom(rectWtLbl_[WT_INDEX_GROSS], rectWtUnits_[WT_INDEX_NET]);

        rectWeightBackground_.SetLocationAndSizeFrom(rectWtLbl_[WT_INDEX_GROSS], rectWtLbl_[WT_INDEX_GROSS]);
        rectWeightBackground_.SetX(0);
        rectWeightBackground_.SetWidth(dspMain.GetWidth() - 1);

        rect.SetTopBasedOnFont(formFontSetSmall.GetFont(fontIndexPrompt), 12.0);
        rect.SetHeightBasedOnFont(formFontSetSmall.GetFont(fontIndexPrompt), 1.0);
        rect.SetX(0);
        rect.SetWidth((dspMain.GetWidth() / 2) - 1);
        rectErrorMsg_ = rect;

    rectDateTime_.SetLeftAndWidthBasedOnDspArea(dspMain, 0.75, 0.22);
    rectDateTime_.SetY(0.0);
    rectDateTime_.SetHeight(BORDER_BOX_HEIGHT + 3);

    rectOperator_.SetLeftAndWidthBasedOnDspArea(dspMain, 0.03, 0.24);
    rectOperator_.SetY(0.0);
    rectOperator_.SetHeight(BORDER_BOX_HEIGHT + 3);
}

#endif

  1. Most older app projects have almost all of the code in the a single cpp file. Functions for displaying dynamic data on the main screen are usually named similar to ShowXXXX such as ShowDateTime, ShowGTN, etc... Cut the code of these functions from the main source file and paste them into the wght_screen.cpp file. Then update the function names to be class members. It will also be necessary to add the function names to the wght_screen.h class definition under the SetupDisplayLocations function prototype. In the class definition do not include the CWeighingScreen:: in front of the function names.

For example ShowGTN cut from the main cpp, pasted into wght_screen.cpp and made a member function may look like this:

void CWeighingScreen::ShowGTN(void)
{
    SetCurColor(nColorGreen);
    SetBkColor(nColorBlack);
    DisplayText(GROSS_LBL_X, GROSS_LBL_Y, LANG(STR_GROSS_LABEL), 0, BIG_FONT);

    if(curScale >= 0 && GetWtMode(curScale) == wtmode_net) {
        DisplayText(TARE_LBL_X, TARE_WT_Y, LANG(STR_TARE_LABEL), 0, BIG_FONT);
        DisplayText(NET_LBL_X, NET_WT_Y, LANG(STR_NET_LABEL), 0, BIG_FONT);
    }
}

The header wght_screen.h should have a corresponding line added under public: such as:

    void ShowGTN(void);

This should not have the class name CWeighingScreen:: Confirm that the line in the header ends with a semicolon.

  1. Modify this function for new style display such as:
void CWeighingScreen::ShowGTN(void)
{
#if ARM64
    SetCurColor(COLOR_INFO);
    fontBigLabel.DisplayTextCairo(rectWtLbl_[WT_INDEX_GROSS], LANG(STR_GROSS_LABEL));

    if(curScale >= 0 && GetWtMode(curScale) == wtmode_net) {
        fontBigLabel.DisplayTextCairo(rectWtLbl_[WT_INDEX_TARE], LANG(STR_TARE_LABEL));
        fontBigLabel.DisplayTextCairo(rectWtLbl_[WT_INDEX_NET], LANG(STR_NET_LABEL));
    }
#else
    SetCurColor(nColorGreen);
    SetBkColor(nColorBlack);
    DisplayText(GROSS_LBL_X, GROSS_LBL_Y, LANG(STR_GROSS_LABEL), 0, BIG_FONT);

    if(curScale >= 0 && GetWtMode(curScale) == wtmode_net) {
        DisplayText(TARE_LBL_X, TARE_WT_Y, LANG(STR_TARE_LABEL), 0, BIG_FONT);
        DisplayText(NET_LBL_X, NET_WT_Y, LANG(STR_NET_LABEL), 0, BIG_FONT);
    }
#endif
}
  1. Add the following header include to the main cpp file
    #include "wght_screen.h"
    
  1. Add an instance of the CWeighingScreen above all the functions such as:
    CWeighingScreen weightScreen;
    
  1. Find the InitLCD function call and change as follows:
void IndStartup(void)
{
#if ARM64
        InitLCD(DSP_INIT_NEW_STYLE_APP);
        AppDisplayZoomInit();
        InitFonts();
        weightScreen.SetupDisplayLocations();
        EnableFullScreenMode();
#else
        InitLCD();
#endif
// ... Additional code
}

The EnableFullScreenMode() is optional but recommended for new apps. When this is included the app will stay in the zoomed state and only show a keypad for specified form input fields. This is easier for users of the app. However, this may require a little more work to make the app fully functional. All menu screens must have an Exit button provided since there is no always shown navigation keypad with arrow buttons. Input screens should have ESC or Cancel and Ok buttons. The apphelpers.cpp/.h provides helpers to simplify these changes.

  1. Modify all the references in the main .cpp file to ShowXXXX functions such as ShowGTN() to call the functions within the weightScreen instance:
    weightScreen.ShowGTN();
    
  1. Remove the function prototype lines for the ShowXXXX functions that were moved to the wght_screen.h from the main header file.
  1. Search for all menu and inputs forms such as search for "FORM_INIT" make appropriate changes to use new style FORM_ADD_INPUT2 instead of FORM_ADD_INPUT and FORM_ADD_BUTTON2 instead of FORM_ADD_BUTTON such as:

Following is an example input form if EnableFullScreenMode is not used.

void PresetScreen(void)
{
#if ARM64
        CFormRect rect, rectInp;

        FORM_INIT(Setup, EventPresetScreenShow, NULL, NULL, NULL, nFormFlgShowHelp);

        SetupInputFormToUseFontSet(formSetup, rect, rectInp, "Total Violation: ");

        FORM_ADD_INPUT2(Setup, Thresh,  rect, rectInp, "On Threshold: ", 6, 0, 999999, NULL, &g_setup.onThresh, FORM_FLOAT, NULL, "Enter the on threshold");
        AdvanceInputRects(rect, rectInp);
        FORM_ADD_INPUT2(Setup, ViolTot, rect, rectInp, "Total Violation: ", 6, 0, 999999, NULL, &g_setup.violWt[0], FORM_FLOAT, NULL, "Enter violation weight for total");
        AdvanceInputRects(rect, rectInp);
        FORM_ADD_INPUT2(Setup, Viol1,   rect, rectInp, "P1 Violation: ", 6, 0, 999999, NULL, &g_setup.violWt[1], FORM_FLOAT, NULL, "Violation weight for P1");
#else
        FORM_INIT(Setup, EventPresetScreenShow, NULL, NULL, NULL, nFormFlgShowHelp);
        FORM_ADD_INPUT(Setup, Thresh, 0, FONT_HEIGHT * 2, "On Threshold: ", 6, 0, 999999, NULL, &g_setup.onThresh, FORM_FLOAT, NULL, "Enter the on threshold");
        FORM_ADD_INPUT(Setup, ViolTot, 0, FONT_HEIGHT * 4, "Total violation: ", 6, 0, 999999, NULL, &g_setup.violWt[0], FORM_FLOAT, NULL, "Enter violation weight for total");
        FORM_ADD_INPUT(Setup, Viol1, 0, FONT_HEIGHT * 6, "P1 Violation: ", 6, 0, 999999, NULL, &g_setup.violWt[1], FORM_FLOAT, NULL, "Violation weight for P1");
#endif
        FORM_SHOW(Setup);
        int n = FORM_RUN(Setup);
        if (n != FORM_RESULT_ESC) {
                SaveSetup();
        }
        FORM_HIDE(Setup);
}

In the above example notice after FORM_INIT the function SetupInputFormToUseFontSet is called. SetupInputFormToUseFontSet is a helper function defined in apphelpers.cpp. This gives the form a pointer to the fonts that were initialized previously. The function also sets the starting positions of the rect, and rectInp rectangles that are used to define where to show the prompts and input fields. The final parameter is a string used to determine the width of the prompts. This should be the longest prompt text in the form. The AdvanceInputRects function call is used between FORM_ADD_INPUT2 calls to move the rect and rectInp down an appropriate amount for the next input.

Following is an example input form when EnableFullScreenMode is used.

void PresetScreen(void)
{
#if ARM64
        CFormRect rectInpBtn;
        CFormButton btnOk;

        FORM_INIT(Setup, EventPresetScreenShow, NULL, NULL, NULL, nFormFlgShowHelp | nFormFlgAutoPresentPopup | nFormFlgShowPopupTabKeypad);

        SetupInputFormToUseFontSet(formSetup, rectInpBtn, 0.45, 1.3);

        FORM_ADD_INPUT2(Setup, Thresh,  rectInpBtn, rectKeypad, "On Threshold: ",    6, 0, 999999, NULL, &g_setup.onThresh, FORM_FLOAT | FORM_POPUP_LEFT_PROMPT, NULL, "Enter the on threshold");
        rectInpBtn += inputAdvanceY;
        FORM_ADD_INPUT2(Setup, ViolTot, rectInpBtn, rectKeypad, "Total Violation: ", 6, 0, 999999, NULL, &g_setup.violWt[0], FORM_FLOAT | FORM_POPUP_LEFT_PROMPT, NULL, "Enter violation weight for total");
        rectInpBtn += inputAdvanceY;
        FORM_ADD_INPUT2(Setup, Viol1,   rectInpBtn, rectKeypad, "P1 Violation: ",    6, 0, 999999, NULL, &g_setup.violWt[1], FORM_FLOAT | FORM_POPUP_LEFT_PROMPT, NULL, "Violation weight for P1");

        formSetup.LeftAlignPromptInputs(inpThresh, inpViol1);

        AddFormOkButton(formSetup, btnOk);
#else
        FORM_INIT(Setup, EventPresetScreenShow, NULL, NULL, NULL, nFormFlgShowHelp);
        FORM_ADD_INPUT(Setup, Thresh, 0, FONT_HEIGHT * 2, "On Threshold: ", 6, 0, 999999, NULL, &g_setup.onThresh, FORM_FLOAT, NULL, "Enter the on threshold");
        FORM_ADD_INPUT(Setup, ViolTot, 0, FONT_HEIGHT * 4, "Total violation: ", 6, 0, 999999, NULL, &g_setup.violWt[0], FORM_FLOAT, NULL, "Enter violation weight for total");
        FORM_ADD_INPUT(Setup, Viol1, 0, FONT_HEIGHT * 6, "P1 Violation: ", 6, 0, 999999, NULL, &g_setup.violWt[1], FORM_FLOAT, NULL, "Violation weight for P1");
#endif
        FORM_SHOW(Setup);
        int n = FORM_RUN(Setup);
        if (n != FORM_RESULT_ESC) {
                SaveSetup();
        }
        FORM_HIDE(Setup);
}

In the above example FORM_INIT has additional flags nFormFlgAutoPresentPopup | nFormFlgShowPopupTabKeypad. This is to show the popup keypad automatically and include the small tab keypad to navigate between input fields.

The function SetupInputFormToUseFontSet is called after FORM_INIT. SetupInputFormToUseFontSet is a helper function defined in apphelpers.cpp. This gives the form a pointer to the fonts that were initialized previously. The function also sets the starting positions of the rectInpBtn rectangle that is used to define where to show the prompts and input fields. The following parameter is a value that is a percentage of the display area to set the width of the input fields. The optional forth parameter is the height of the input fields based on the font height.

The FORM_ADD_INPUT2 statements have the rectKeypad for the second rectangle parameter. This is defined in apphelpers.cpp to specify that the keypad will be near the bottom of the screen. An additional flag FORM_POPUP_LEFT_PROMPT is used for inputs to specify that the prompt text will be left of the input field.

The formSetup.LeftAlignPromptInputs(inpThresh, inpViol1) Statement is used to align the input fields. This function scans the input fields from Thresh through Viol1 and finds the longest prompt text. It then sets all the input field coordinates all of these inputs so that the input prompts are lined up based on the longest prompt.

The popup tab keypad provides an ESC (escape) key. However, an "Ok" button is necessary to complete the form saving changes. The AddFormOkButton() function is used to provide the "Ok" button. The AddFormOkButton() function is defined in apphelpers.cpp.

Another input form style is useful when EnableFullScreenMode is used and the form has mostly selection items and numeric inputs.

        CFormRect rectInpBtn;
        CFormButton btnCancel, btnOk;

        FORM_INIT(ScaleInfo, EventConfigScaleInfoShow, NULL, NULL, NULL, nFormFlgShowHelp);

        SetupInputFormToUseFontSet(formScaleInfo, rectInpBtn, 0.18);

        FORM_ADD_INPUT2(ScaleInfo, Threshold,   rectInpBtn, CFormRect::zero, "On Threshold:", 6, 0, 80000, NULL, &threshold_, FORM_FLOAT, NULL, NULL);
        rectInpBtn.AdvanceX(INPUT_BUTTON_X_MARGIN);
        FORM_ADD_INPUT2(ScaleInfo, Threshold2,  rectInpBtn, CFormRect::zero, "Off Threshold:", 6, 0, 80000, NULL, &lowThreshold_, FORM_FLOAT, NULL, NULL);

        rectInpBtn += buttonAdvanceY;
        rectInpBtn.SetLeftAndWidthBasedOnDspArea(formScaleInfo.GetDspArea(), 0.03, 0.32);

        FORM_ADD_INPUT2(ScaleInfo, ShowTrfLght, rectInpBtn, CFormRect::zero, "Show Traffic Light Graphic:", 4, 0, SCALEINFO_FLAG_BIT_SHOW_TRAFFIC_LIGHT, NULL, &flags_, FORM_UINT32_YESNO, NULL, NULL);
        rectInpBtn.AdvanceX(INPUT_BUTTON_X_MARGIN);

        FORM_ADD_INPUT2(ScaleInfo, ManualTrf,   rectInpBtn, CFormRect::zero, "Manual Traffic Release:", 4, 0, SCALEINFO_FLAG_BIT_MANUAL_TRAFFIC_RELEASE, NULL, &flags_, FORM_UINT32_YESNO, NULL, NULL);

        AddFormCancelOkButtons(formScaleInfo, btnCancel, btnOk);

        formScaleInfo.SetUserData(scaleNum_);

        FORM_SHOW(ScaleInfo);
        n = FORM_RUN(ScaleInfo);
        FORM_HIDE(ScaleInfo);

In the above example instead of prompts on the left and inputs to the right the input items appear as buttons. The "On Threshold" and "Off Threshold" items use CFormRect::zero instead of rectKeypad. When pressed they will show the numeric input keypad directly below the selected button. The "Traffic" items are Yes/No inputs which always show the selection at the input location. They also have CFormRect::zero. This type of input form is simple and works best without the popup tab keypad. Since there is no popup tab keypad with an ESC (escape) key the form has "Cancel" and "Ok" buttons. The AddFormCancelOkButtons() function is defined in apphelpers.cpp.

EVENT(FileOperationShow)
{
   ClearScreenAndShowTitle(pForm, "File Operation");
   return 0;
}

void FileOperation(void)
{
#if ARM64
        CFormRect rect;
        CFormButton btnExit;

        FORM_INIT(Update, EventFileOperationShow, NULL, NULL, NULL, 0);

        SetupMenuFormToUseFontSet(formUpdate, rect, MENU_BTN_WIDE_WIDTH);

        FORM_ADD_BUTTON2(Update, Export, rect, "Export",        'X',  EventExport,      FORM_BUTTON_SHADOW);
        rect += btnAdvanceY;
        FORM_ADD_BUTTON2(Update, Import, rect, "Import",        'I',  EventImport,      FORM_BUTTON_SHADOW);

        AddFormExitButton(formUpdate, btnExit);
#else
        FORM_INIT(Update, EventFileOperationShow, NULL, NULL, NULL, 0);

        FORM_ADD_BUTTON(Update, Export, MENU_COL1_X,    MENU_ROW1_Y,    " Export ", 'X', EventExport, FORM_BUTTON_INVERT);
        FORM_ADD_BUTTON(Update, Import, MENU_COL1_X,    MENU_ROW2_Y,    " Import ", 'I', EventImport, FORM_BUTTON_INVERT);
#endif

        FORM_SHOW(Update);
        FORM_RUN(Update);
        FORM_HIDE(Update);
}

In the above example notice after FORM_INIT the function SetupMenuFormToUseFontSet is called. SetupMenuFormToUseFontSet is a helper function defined in apphelpers.cpp. This gives the form a pointer to the fonts that were initialized previously. The function also sets the starting position of the rect rectangle that is used to define where to show the button.

Notice between FORM_ADD_BUTTON2 lines the rect is advanced by rect += btnAdvanceY; The CFormRect class contains multiple values. The += operator is overloaded to allow the advance as shown. The AdvanceInputRects function from the previous example is actually doing the same thing, but for input forms to advance both the prompt and the input rectangles.

static inline void AdvanceInputRects(CFormRect& rect, CFormRect& rectInp)
{
        rect += inputAdvanceY;
        rectInp += inputAdvanceY;
}

Legacy code forms normally used fixed X,Y positions. It is often simpler and easier to maintain to just advance the positions. There are cases such as two column menus where at some point between FORM_ADD_BUTTON2 lines the rect position is reset to start the second column.

The style of the buttons should be changed from FORM_BUTTON_INVERT to FORM_BUTTON_SHADOW for the new 825 Gen2 button appearance.

Some apps, especially older ones may use lib825 instead of the newer lib825ev. In addition to CForm (FORM_INIT) a different method of creating forms exists in the older lib825 called DynamicForm. These apps may also use a C++ class called the Application class. To update apps using lib825 to new style graphics it would be best to convert the app to a lib825ev (event style) app first. Depending on the size of the app this could be a much more involved process.

Apps using lib825 or lib825ev may also use FormLCD which defines forms based on structs. It is relatively simple to convert these apps to CForm (FORM_INIT) style, but will still take more time. Refer to the example below:

#define nTimeItems 3
const struct form_item_struct frmtm[nTimeItems] = {
{
   // X  Y    Prompt      Len   Min  Max   Flag       Choices  Help
   {  0, 3,  "Hour:   ",   2,   0,   23,   FORM_UINT8, NULL, "Enter the hour in 24 hour time\r3 p.m. = 15" },
   {  0, 5,  "Minute: ",   2,   0,   59,   FORM_UINT8, NULL, "Enter the minutes" },
   {  0, 7,  "Second: ",   2,   0,   59,   FORM_UINT8, NULL, "Enter the seconds" }
};

int SetTime(void)
{
    int n;
    void* pData[nTimeItems];

    pData[0] = &g_datetime.hour;
    pData[1] = &g_datetime.minute;
    pData[2] = &g_datetime.second;

    ClearLCD();
    SetCurColor(COLOR_INFO);
    PrintLCD("Set Time");

    SetCurColor(nColorGreen);
    n = FormLCD((struct form_item_struct*)frmtm, pData, nTimeItems, NULL, nFormFlgShowHelp);
    if(n) {
        // Set the time
        // ...
    }
    return n;
}

Notice in the above example a const structure defines the form. An array of void pointers (pData) is setup to point to the data items to be read/changed when the form runs. This array is passed to the FormLCD function. The above code converted to CForm style is:

EVENT(TimeShow)
{
   ClearLCD();
   SetCurColor(COLOR_ATTENTION);
   PrintLCD("Set Time");
   return 0;
}

int SetTime(void)
{
   int n;
   FORM_INIT(Time, EventTimeShow, NULL, NULL, NULL, nFormFlgShowHelp);
   FORM_ADD_INPUT(Time, Hour,   FONT_WIDTH * 0, FONT_HEIGHT * 3, "Hour: ",   2, 0, 23, NULL, &g_datetime.hour,   FORM_UINT8, NULL, "Enter the hour in 24 hour time\r3 p.m. = 15");
   FORM_ADD_INPUT(Time, Minute, FONT_WIDTH * 0, FONT_HEIGHT * 5, "Minute: ", 2, 0, 59, NULL, &g_datetime.minute, FORM_UINT8, NULL, "Enter the minutes");
   FORM_ADD_INPUT(Time, Second, FONT_WIDTH * 0, FONT_HEIGHT * 7, "Second: ", 2, 0, 59, NULL, &g_datetime.second, FORM_UINT8, NULL, "Enter the seconds");

   FORM_SHOW(Time);
   n = FORM_RUN(Time);
   FORM_HIDE(Time);
   if(n != FORM_RESULT_ESC) {
        // Set the time
        // ...
    }
    return n;
}

The above code can then easily be converted to the new style graphics using FORM_ADD_INPUT2 as shown earlier.

Last modified 2 hours ago Last modified on 07/22/25 13:16:27
Note: See TracWiki for help on using the wiki.