= 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 [wiki:UpdatingLegacyApps Updating Legacy Apps]) and Debug-ARM825-SIM (See [wiki:Simulating825gen2 Simulating 825gen2 Apps]). 2. 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. 3. Copy the //wght_screen.h// from a standard project if possible similar to the project being updated. {{{#!c++ /* * 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 { #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 public: CWeighingScreen(void) { } #if ARM64 void SetupDisplayLocations(void); #endif }; }}} 4. Create a source file wght_screen.cpp in the src folder. Do not just copy this entire file from a standard project. Copy the SetupDisplayLocations portion of the file from a standard app. {{{#!c++ #include "cardinal825.h" #include "appinfo.h" #include "apphelpers.h" #include "langstr.h" 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; } #endif }}} 5. Most older app project have almost all of the code in the a single cpp file. Most of the functions for displaying dynamic data on the main screen are named Show//XXXX// 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 or make sure they match names already in wght_screen.h. For example ShowDatetime will be: {{{ void CWeighingScreen::ShowDateTime(void) { } }}} 6. Find the InitLCD function call and change as follows: {{{#!c++ void IndStartup(void) { #if ARM64 InitLCD(DSP_INIT_NEW_STYLE_APP); dspMain.SetZoomWidth(0, dspMain.GetZoomWidth(1)); if(dsp_height > 800) { dspMain.SetZoomHeight(0, (int)(dspMain.GetZoomHeight(1) * 0.84)); } InitFonts(); SetupDisplayLocations(); #else InitLCD(); #endif // ... Additional code } }}} 5. Modify functions that do display operations such as shown: {{{#!c++ void ShowGTN(void) { #if ARM64 SetCurColor(COLOR_INFO); SetBkColor(nColorWhite); fontBigLabel.DisplayText(rectWtLbl[WT_INDEX_GROSS], LANG(STR_GROSS_LABEL)); if (curScale >= 0 && GetWtMode(curScale) == wtmode_net) { fontBigLabel.DisplayText(rectWtLbl[WT_INDEX_TARE], LANG(STR_TARE_LABEL)); fontBigLabel.DisplayText(rectWtLbl[WT_INDEX_NET], LANG(STR_NET_LABEL)); } #else SetCurColor(nColorGreen); SetBkColor(nColorBlack); DisplayText(GROSS_LBL_X, GROSS_WT_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); } SetBkColor(nColorBlack); #endif } }}} 6. 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: {{{#!c++ 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. {{{#!c++ EVENT(FileOperationShow) { ClearScreenAndShowTitle(pForm, "File Operation"); return 0; } void FileOperation(void) { #if ARM64 CFormRect rect; 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); #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. {{{#!c++ 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: {{{#!c++ #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: {{{#!c++ 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.