How to Create a Custom Calendar/Date Picker

Last modified by Microchip on 2025/01/09 09:58

Introduction

A date picker dialog box Graphical User Interface (GUI) is a user interface component that allows users to select a date from a calendar-like interface. This component is commonly used in applications where users must input dates, such as booking systems, scheduling applications, and forms.

This user guide demonstrates how to use the Keypad widget and other MGS widgets to create a pop-up, custom calendar, or date picker that sets the date in the application.

MGS Example Project

Refer to the project in GitHub for the example.

MGS Simulator Output

This is how the application runs:

  • Pressing the Set Date button opens the calendar/date picker dialog box. The default month and year is January 2025.
  • Pressing the << or >> buttons will show the current month's calendar for the previous or next year, respectively.
  • Pressing the < or > buttons will show the current year's calendar for the previous or next month, respectively.
  • Pressing any of the days will update the date to the selected day of the month and year, and hide the calendar dialog box.
  • Pressing Close will hide the dialog box without updating the date.
Figure 1: Calendar and Date-picker UI (interactive)

Back to Top

MGS Harmony Composer Design

Figure 2 shows the screen design in MGS Harmony Composer. The On Show, On Hide, and On Update event callbacks are enabled for this screen. These callbacks will be used to initialize and update the screen at runtime.

Composer Design

Figure 2: Composer Design

The visible screen area contains an Image widget with the MGS logo and a Button widget that shows the calendar/date-picker dialog box when pressed and the selected date.

The Button widget is configured as shown in Figure 3, and the Released event is enabled. This tells the graphics library to call the event callback when the button is pressed and released.

Main Screen

Figure 3: Main Screen

Off-screen is the pnlCalendarDialog Panel widget, which is used to contain the widgets used to create the calendar dialog box.

Button widgets show the next or previous month or year. A Close button is used to hide the calendar dialog box. For each of these buttons, the Released event is enabled so the graphics library calls the application's event callback function when these buttons are pressed and then released.

Calendar Dialog Box

Figure 4: Calendar dialog box

A Keypad widget is configured to show the days in the specified month in the individual cells or keys. The Key Clicked event callback is enabled so that the graphics library calls the application-defined callback function when any of the cells are pressed to pick a date.

Keypad Widget

Figure 5: Keypad Widget for Calendar days

The cells in the Keypad widget are configured using the Configure option. 

Cell configuration

Figure 6: Cell Configuration

Each cell has a unique image asset for the pressed and released icon, and the image position is set to 'Behind' so the text on each cell is shown on top of the images. Note that there is no text assigned on the cells in the MGS Composer design since the text will be set at run-time by the application.

These image assets were imported and configured using the Image Manager. The source image files are found in the project's assets  directory.

Image Assets

Figure 7: Image Assets

String assets were also added for the labels used in the design, including the strings for all the months and days of the week.

String Assets

Figure 8: String Assets

A single font asset is used for all the strings in the design. Since this font will be used for the run-time strings in the application,  it is configured so that the range includes the Latin Standard glyphs.

The appropriate size (14) is set and Anti-aliased is enabled to show text with smooth edges.

Single Font Asset

Figure 9: Single Font Asset

Back to Top

Application Code

The application code that manages the screen behavior and the callback functions for handling the screen and widget events are defined in the app_screen.c file. 

Back to Top

Helper Functions

A helper function is used to determine the day of the week for a specified year, month, and day using the Sakamoto method.

/*
 * Sakamoto's method for calculating day of week for given day
 * Source: Wikipedia
 */

static uint32_t dayofweek(uint32_t y, uint32_t m, uint32_t d)

Another helper function is defined to return the day, given the start day of the month and the cell row and column. This is used to set the day for each cell in the keypad widget.

/*
 * Helper function that gets the day from specified row and col
 * startDay is the day of week for the first day of the month
 *
 * Returns <= 0 if cell doesn't map to a day
 */

static int32_t getDayByCell(uint32_t startDay, uint32_t cellRow, uint32_t cellCol)

Back to Top

Generating the days of the month

The function APP_CreateCalendar is used to configure the calendar dialog box widgets and set the days on the Keypad widget cells for the specified month and year.

/* Configures the keypad widget based on the specified year and month */
static void APP_CreateCalendar(uint32_t year, uint32_t month)

The text for the day on each cell is generated using Fixed Strings.

static leFixedString daysFixedStr[MAX_NUM_DAYS]
static leChar daysStrBuff[MAX_NUM_DAYS][DAY_STR_SIZE]

These Fixed Strings are used to set the day on a cell that contains a valid day of the month. These cells are also enabled so they respond to touch events and the cell pressed/released images are set.

/* If a valid day, set the cell string and images */
snprintf(dayStr, DAY_STR_SIZE + 1, "%u", day);
daysFixedStr[day - 1].fn->setFromCStr(&daysFixedStr[day - 1], dayStr);
cell->fn->setString(cell, (leString *) &daysFixedStr[day - 1]);
cell->fn->setPressedImage(cell, &ButtonDown);
cell->fn->setReleasedImage(cell, &ButtonUp);
                   
/* Enable the cell so it can be selected */
cell->fn->setEnabled(cell, LE_TRUE);

For cells that do not contain a valid day of the month, the cell is not enabled so it doesn't receive any touch input and hidden by clearing the icon images.

/* If a no valid day, clear the cell */
cell->fn->setString(cell, (leString *) NULL);
cell->fn->setPressedImage(cell, NULL);
cell->fn->setReleasedImage(cell, NULL);
                   
/* Disable the cell so it cannot be selected */
cell->fn->setEnabled(cell, LE_FALSE);

In the screen OnShow event callback, this function is called during boot to initialize the Fixed Strings and create the calendar for the default month and year.

/* Screen OnShow handler  */
void Screen0_OnShow(void)

The monthly calendar is also recreated when the user changes the month and year using the next and previous month or year buttons.

Back to Top

Date Picker Function

A date is picked when the user presses any of the cells on the Keypad widget. The Keypad widget's OnKeyClick event is enabled so that the application-defined key click event callback function is called. 

/* Key event handler for the cells. This is called when a user presses an enabled cell */
void event_Screen0_keyCalendar_OnKeyClick(leKeyPadWidget* wgt, leButtonWidget* cell, uint32_t row, uint32_t col)

The callback function uses the helper functions to get the day of the current month and year, based on the row and column number of the clicked cell. The function will then update the text on the Set Date button on the main screen to show the selected date.

Back to Top

Learn More

Back to Top