text: //*****************************************************************************
  //
  // clocksetwidget.c - A widget for setting clock date/time.
  //
  // Copyright (c) 2011-2014 Texas Instruments Incorporated.  All rights reserved.
  // Software License Agreement
  // 
  // Texas Instruments (TI) is supplying this software for use solely and
  // exclusively on TI's microcontroller products. The software is owned by
  // TI and/or its suppliers, and is protected under applicable copyright
  // laws. You may not combine this software with "viral" open-source
  // software in order to form a larger program.
  // 
  // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
  // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
  // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
  // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
  // DAMAGES, FOR ANY REASON WHATSOEVER.
  // 
  // This is part of revision 2.1.0.12573 of the EK-LM4F232 Firmware Package.
  //
  //*****************************************************************************
  
  #include <stdint.h>
  #include <stdbool.h>
  #include "inc/hw_types.h"
  #include "driverlib/debug.h"
  #include "utils/uartstdio.h"
  #include "grlib/grlib.h"
  #include "grlib/widget.h"
  #include "utils/ustdlib.h"
  #include "clocksetwidget.h"
  
  //*****************************************************************************
  //
  //! \addtogroup clocksetwidget_api
  //! @{
  //
  //*****************************************************************************
  
  //*****************************************************************************
  //
  // This is a custom widget for setting the date/time of a clock.  The widget
  // will display the year, month, day, hour and minute on the display.  The
  // user can highlight the fields with the left/right keys, and can change the
  // value of each with the up/down keys.  When finished the user highlights
  // the OK field on the screen and presses the select button.
  //
  //*****************************************************************************
  
  //*****************************************************************************
  //
  // Define indices for each of the fields used for date and time.
  //
  //*****************************************************************************
  #define FIELD_YEAR              0
  #define FIELD_MONTH             1
  #define FIELD_DAY               2
  #define FIELD_HOUR              3
  #define FIELD_MINUTE            4
  #define FIELD_OK                5
  #define FIELD_CANCEL            6
  #define FIELD_LAST              6
  #define NUM_FIELDS              7
  
  //*****************************************************************************
  //
  //! Paints the clock set widget on the display.
  //!
  //! \param psWidget is a pointer to the clock setting widget to be drawn.
  //!
  //! This function draws the date and time fields of the clock setting widget
  //! onto the display.  One of the fields can be highlighted.  This is
  //! called in response to a \b WIDGET_MSG_PAINT message.
  //!
  //! \return None.
  //
  //*****************************************************************************
  static void
  ClockSetPaint(tWidget *psWidget)
  {
      tClockSetWidget *psClockWidget;
      tContext sContext;
      tRectangle sRect, sRectSel;
      struct tm *psTime;
      char pcBuf[8];
      int32_t i32X, i32Y, i32Width, i32Height;
      uint32_t ui32Idx, ui32FontHeight, ui32FontWidth, ui32SelWidth;
  
      //
      // Check the arguments.
      //
      ASSERT(psWidget);
      ASSERT(psWidget->psDisplay);
  
      //
      // Convert the generic widget pointer into a clock set widget pointer.
      //
      psClockWidget = (tClockSetWidget *)psWidget;
      ASSERT(psClockWidget->psTime);
  
      //
      // Get pointer to the time structure
      //
      psTime = psClockWidget->psTime;
  
      //
      // Initialize a drawing context.
      //
      GrContextInit(&sContext, psWidget->psDisplay);
  
      //
      // Initialize the clipping region based on the extents of this widget.
      //
      GrContextClipRegionSet(&sContext, &(psWidget->sPosition));
  
      //
      // Set the font for the context, and get font height and width - they
      // are used a lot later.
      //
      GrContextFontSet(&sContext, psClockWidget->psFont);
      ui32FontHeight = GrFontHeightGet(psClockWidget->psFont);
      ui32FontWidth = GrFontMaxWidthGet(psClockWidget->psFont);
  
      //
      // Fill the widget with the background color.
      //
      GrContextForegroundSet(&sContext, psClockWidget->ui32BackgroundColor);
      GrRectFill(&sContext, &sContext.sClipRegion);
  
      //
      // Draw a border around the widget
      //
      GrContextForegroundSet(&sContext, psClockWidget->ui32ForegroundColor);
      GrContextBackgroundSet(&sContext, psClockWidget->ui32BackgroundColor);
      GrRectDraw(&sContext, &sContext.sClipRegion);
  
      //
      // Compute a rectangle for the screen title.  Put it at the top of
      // the widget display, and sized to be the height of the font, plus
      // a few pixels of space.
      //
      sRect.i16XMin = sContext.sClipRegion.i16XMin;
      sRect.i16XMax = sContext.sClipRegion.i16XMax;
      sRect.i16YMin = sContext.sClipRegion.i16YMin;
      sRect.i16YMax = ui32FontHeight * 2;
      GrRectDraw(&sContext, &sRect);
  
      //
      // Print a title for the widget
      //
      GrContextFontSet(&sContext, psClockWidget->psFont);
      GrStringDrawCentered(&sContext, "CLOCK SET", -1,
                           (1 + sRect.i16XMax - sRect.i16XMin) / 2,
                           (1 + sRect.i16YMax - sRect.i16YMin) / 2, 1);
  
      //
      // Reset the rectangle to cover the non-title area of the display
      //
      sRect.i16YMin = sRect.i16YMax + 1;
      sRect.i16YMax = sContext.sClipRegion.i16YMax;
  
      //
      // Compute the width and height of the area remaining for showing the
      // clock fields.
      //
      i32Width = 1 + (sRect.i16XMax - sRect.i16XMin);
      i32Height = 1 + (sRect.i16YMax - sRect.i16YMin);
  
      //
      // Compute the X and Y starting point for the row that will show the
      // date.
      //
      i32X = sRect.i16XMin + (i32Width - (ui32FontWidth * 10)) / 2;
      i32Y = sRect.i16YMin + ((i32Height * 1) / 6) - (ui32FontHeight / 2);
  
      //
      // Draw the date field separators on the date row.
      //
      GrStringDraw(&sContext, "/", -1, i32X + (ui32FontWidth * 4), i32Y, 0);
      GrStringDraw(&sContext, "/", -1, i32X + (ui32FontWidth * 7), i32Y, 0);
  
      //
      // Compute the X and Y starting point for the row that will show the
      // time.
      //
      i32X = sRect.i16XMin + (i32Width - (ui32FontWidth * 5)) / 2;
      i32Y = sRect.i16YMin + ((i32Height * 3) / 6) - (ui32FontHeight / 2);
  
      //
      // Draw the time field separators on the time row.
      //
      GrStringDraw(&sContext, ":", -1, i32X + (ui32FontWidth * 2), i32Y, 0);
  
      //
      // Process each of the fields to be shown on the widget
      //
      for(ui32Idx = 0; ui32Idx < NUM_FIELDS; ui32Idx++)
      {
          //
          // Compute the X and Y for the text for each field, and print the
          // text into a buffer.
          //
          switch(ui32Idx)
          {
              //
              // Year
              //
              case FIELD_YEAR:
              {
                  usnprintf(pcBuf, sizeof(pcBuf), "%4u", psTime->tm_year+1900);
                  i32X = sRect.i16XMin + (i32Width - (ui32FontWidth * 10)) / 2;
                  i32Y = sRect.i16YMin + ((i32Height * 1) / 6) -
                         (ui32FontHeight / 2);
                  ui32SelWidth = 4;
                  break;
              }
  
              //
              // Month
              //
              case FIELD_MONTH:
              {
                  usnprintf(pcBuf, sizeof(pcBuf), "%02u", psTime->tm_mon + 1);
                  i32X += ui32FontWidth * 5;
                  ui32SelWidth = 2;
                  break;
              }
  
              //
              // Day
              //
              case FIELD_DAY:
              {
                  usnprintf(pcBuf, sizeof(pcBuf), "%02u", psTime->tm_mday);
                  i32X += ui32FontWidth * 3;
                  ui32SelWidth = 2;
                  break;
              }
  
              //
              // Hour
              //
              case FIELD_HOUR:
              {
                  usnprintf(pcBuf, sizeof(pcBuf), "%02u", psTime->tm_hour);
                  i32X = sRect.i16XMin + (i32Width - (ui32FontWidth * 5)) / 2;
                  i32Y = sRect.i16YMin + ((i32Height * 3) / 6) -
                         (ui32FontHeight / 2);
                  ui32SelWidth = 2;
                  break;
              }
  
              //
              // Minute
              //
              case FIELD_MINUTE:
              {
                  usnprintf(pcBuf, sizeof(pcBuf), "%02u", psTime->tm_min);
                  i32X += ui32FontWidth * 3;
                  ui32SelWidth = 2;
                  break;
              }
  
              //
              // OK
              //
              case FIELD_OK:
              {
                  usnprintf(pcBuf, sizeof(pcBuf), "OK");
                  i32X = (i32Width - (ui32FontWidth * 9)) / 2;
                  i32X += sRect.i16XMin;
                  i32Y = ((i32Height * 5) / 6) - (ui32FontHeight / 2);
                  i32Y += sRect.i16YMin;
                  ui32SelWidth = 2;
                  break;
              }
  
              //
              // CANCEL (default case is purely to keep the compiler from
              // issuing a warning that ui32SelWidth may be used ininitialized).
              //
              case FIELD_CANCEL:
              default:
              {
                  usnprintf(pcBuf, sizeof(pcBuf), "CANCEL");
                  i32X += ui32FontWidth * 3;
                  ui32SelWidth = 6;
                  break;
              }
          }
  
  
          //
          // If the current field index is the highlighted field, then this
          // text field will be drawn with highlighting.
          //
          if(ui32Idx == psClockWidget->ui32Highlight)
          {
              //
              // Compute a rectangle for the highlight area.
              //
              sRectSel.i16XMin = i32X;
              sRectSel.i16XMax = (ui32SelWidth * ui32FontWidth) + i32X;
              sRectSel.i16YMin = i32Y - 2;
              sRectSel.i16YMax = ui32FontHeight + i32Y + 2;
  
              //
              // Set the foreground color to the text color, and then fill the
              // highlight rectangle.  The text field will be highlighted by
              // inverting the normal colors.
              // Then draw the highlighting rectangle.
              //
              GrContextForegroundSet(&sContext,
                                     psClockWidget->ui32ForegroundColor);
              GrRectFill(&sContext, &sRectSel);
  
              //
              // Change the foreground color to the normal background color.
              // This will be used for drawing the text for the highlighted
              // field, which has the colors inverted (FG <--> BG)
              //
              GrContextForegroundSet(&sContext,
                                     psClockWidget->ui32BackgroundColor);
          }
          else
          {
              //
              // This text field is not highlighted so just set the normal
              // foreground color.
              //
              GrContextForegroundSet(&sContext,
                                     psClockWidget->ui32ForegroundColor);
          }
  
          //
          // Print the text from the buffer to the display at the computed
          // location.
          //
          GrStringDraw(&sContext, pcBuf, -1, i32X, i32Y, 0);
      }
  }
  
  //*****************************************************************************
  //
  //! Determine the number of days in a month.
  //!
  //! \param tm_mon is the month number to use for determining the number of
  //! days. The month begins with 0 meaning January and 11 meaning December.
  //!
  //! This function returns the highest day number for the specified month.
  //! It does not account for leap year, so February always returns 28 days.
  //!
  //! \return Returns the highest day number for the month.
  //
  //*****************************************************************************
  static uint8_t
  MaxDayOfMonth(uint8_t tm_mon)
  {
      //
      // Process the month
      //
      switch(tm_mon)
      {
          //
          // February returns 28 days
          //
          case 1:
          {
              return(28);
          }
  
          //
          // April, June, September and November return 30
          //
          case 3:
          case 5:
          case 8:
          case 10:
          {
              return(30);
          }
  
          //
          // Remaining months have 31 days.
          //
          default:
          {
              return(31);
          }
      }
  }
  
  //*****************************************************************************
  //
  //! Handle the UP button event.
  //!
  //! \param psWidget is a pointer to the clock setting widget on which to
  //! operate.
  //!
  //! This function handles the event when the user has pressed the up button.
  //! It will increment the currently highlighted date/time field if it is not
  //! already at the maximum value.  If the month or day of the month is being
  //! changed then it enforces the maximum number of days for the month.
  //!
  //! \return Returns non-zero if the button event was handled, and 0 if the
  //! button event was not handled.
  //
  //*****************************************************************************
  static int32_t
  ClockSetKeyUp(tClockSetWidget *psWidget)
  {
      //
      // Get pointer to the time structure to be modified.
      //
      struct tm *psTime = psWidget->psTime;
  
      //
      // Determine which field is highlighted.
      //
      switch(psWidget->ui32Highlight)
      {
          //
          // Increment the year.  Cap it at 2037 to keep things simple.
          //
          case FIELD_YEAR:
          {
              if(psTime->tm_year+1900 < 2037)
              {
                  psTime->tm_year++;
              }
              break;
          }
  
          //
          // Increment the month.  Adjust the day of the month if needed.
          //
          case FIELD_MONTH:
          {
              if(psTime->tm_mon < 11)
              {
                  psTime->tm_mon++;
              }
              if(psTime->tm_mday > MaxDayOfMonth(psTime->tm_mon))
              {
                  psTime->tm_mday = MaxDayOfMonth(psTime->tm_mon);
              }
              break;
          }
  
          //
          // Increment the day.  Cap it at the max number of days for the
          // current value of month.
          //
          case FIELD_DAY:
          {
              if(psTime->tm_mday < MaxDayOfMonth(psTime->tm_mon))
              {
                  psTime->tm_mday++;
              }
              break;
          }
  
          //
          // Increment the hour.
          //
          case FIELD_HOUR:
          {
              if(psTime->tm_hour < 23)
              {
                  psTime->tm_hour++;
              }
              break;
          }
  
          //
          // Increment the minute.
          //
          case FIELD_MINUTE:
          {
              if(psTime->tm_min < 59)
              {
                  psTime->tm_min++;
              }
              break;
          }
  
          //
          // Bad value for field index - ignore.
          //
          default:
          {
              break;
          }
      }
  
      //
      // Since something may have been changed in the clock value, request
      // a repaint of the widget.
      //
      WidgetPaint(&psWidget->sBase);
  
      //
      // Return indication that the button event was handled.
      //
      return(1);
  }
  
  //*****************************************************************************
  //
  //! Handle the DOWN button event.
  //!
  //! \param psWidget is a pointer to the clock setting widget on which to
  //! operate.
  //!
  //! This function handles the event when the user has pressed the down button.
  //! It will decrement the currently highlighted date/time field if it is not
  //! already at the minimum value.  If the month is being changed then it
  //! enforces the maximum number of days for the month.
  //!
  //! \return Returns non-zero if the button event was handled, and 0 if the
  //! button event was not handled.
  //
  //*****************************************************************************
  static int32_t
  ClockSetKeyDown(tClockSetWidget *psWidget)
  {
      //
      // Get pointer to the time structure to be modified.
      //
      struct tm *psTime = psWidget->psTime;
  
      //
      // Determine which field is highlighted.
      //
      switch(psWidget->ui32Highlight)
      {
          //
          // Decrement the year.  Minimum year is 1970.
          //
          case FIELD_YEAR:
          {
              if(psTime->tm_year+1900 > 1970)
              {
                  psTime->tm_year--;
              }
              break;
          }
  
          //
          // Decrement the month.  If the month has changed, check that the
          // day is valid for this month, and enforce the maximum day number
          // for this month.
          //
          case FIELD_MONTH:
          {
              if(psTime->tm_mon > 0)
              {
                  psTime->tm_mon--;
              }
              if(psTime->tm_mday > MaxDayOfMonth(psTime->tm_mon))
              {
                  psTime->tm_mday = MaxDayOfMonth(psTime->tm_mon);
              }
              break;
          }
  
          //
          // Decrement the day
          //
          case FIELD_DAY:
          {
              if(psTime->tm_mday > 1)
              {
                  psTime->tm_mday--;
              }
              break;
          }
  
          //
          // Decrement the hour
          //
          case FIELD_HOUR:
          {
              if(psTime->tm_hour > 0)
              {
                  psTime->tm_hour--;
              }
              break;
          }
  
          //
          // Decrement the minute
          //
          case FIELD_MINUTE:
          {
              if(psTime->tm_min > 0)
              {
                  psTime->tm_min--;
              }
              break;
          }
  
          //
          // Bad value for field index - ignore.
          //
          default:
          {
              break;
          }
      }
  
      //
      // Since something may have been changed in the clock value, request
      // a repaint of the widget.
      //
      WidgetPaint(&psWidget->sBase);
  
      //
      // Return indication that the button event was handled.
      //
      return(1);
  }
  
  //*****************************************************************************
  //
  //! Handle the LEFT button event.
  //!
  //! \param psWidget is a pointer to the clock setting widget on which to
  //! operate.
  //!
  //! This function handles the event when the user has pressed the left button.
  //! It will change the highlighted field to the previous field.  If it is
  //! at the first field in the display, it will wrap around to the last.
  //!
  //! \return Returns non-zero if the button event was handled, and 0 if the
  //! button event was not handled.
  //
  //*****************************************************************************
  static int32_t
  ClockSetKeyLeft(tClockSetWidget *psWidget)
  {
      //
      // If not already at the minimum, decrement the highlighted field index.
      //
      if(psWidget->ui32Highlight)
      {
          psWidget->ui32Highlight--;
      }
      else
      {
          //
          // Already at the first field, so reset to the last field.
          //
          psWidget->ui32Highlight = FIELD_LAST;
      }
  
      //
      // The highlighted field changed, so request a repaint of the widget.
      //
      WidgetPaint(&psWidget->sBase);
  
      //
      // Return indication that the button event was handled.
      //
      return(1);
  }
  
  //*****************************************************************************
  //
  //! Handle the RIGHT button event.
  //!
  //! \param psWidget is a pointer to the clock setting widget on which to
  //! operate.
  //!
  //! This function handles the event when the user has pressed the right button.
  //! It will change the highlighted field to the next field.  If it is already
  //! at the last field in the display, it will wrap around to the first.
  //!
  //! \return Returns non-zero if the button event was handled, and 0 if the
  //! button event was not handled.
  //
  //*****************************************************************************
  static int32_t
  ClockSetKeyRight(tClockSetWidget *psWidget)
  {
      //
      // If not already at the last field, increment the highlighted field index.
      //
      if(psWidget->ui32Highlight < FIELD_LAST)
      {
          psWidget->ui32Highlight++;
      }
      else
      {
          //
          // Already at the last field, so reset to the first field.
          //
          psWidget->ui32Highlight = 0;
      }
  
      //
      // The highlighted field changed, so request a repaint of the widget.
      //
      WidgetPaint(&psWidget->sBase);
  
      //
      // Return indication that the button event was handled.
      //
      return(1);
  }
  
  //*****************************************************************************
  //
  //! Handle the select button event.
  //!
  //! \param psWidget is a pointer to the clock setting widget on which to
  //! operate.
  //!
  //! This function handles the event when the user has pressed the select
  //! button.  If either the OK or CANCEL fields is highlighted, then the
  //! function will call the callback function to notify the application that
  //! an action has been taken and the widget should be dismissed.
  //!
  //! \return Returns non-zero if the button event was handled, and 0 if the
  //! button event was not handled.
  //
  //*****************************************************************************
  static int32_t
  ClockSetKeySelect(tClockSetWidget *psWidget)
  {
      bool bOk;
  
      //
      // Determine if the OK text field is highlighted and set a flag.
      //
      bOk = (psWidget->ui32Highlight == FIELD_OK) ? true : false;
  
      //
      // If there is a callback function installed, and either the OK or CANCEL
      // fields is highlighted, then take action.
      //
      if(psWidget->pfnOnOkClick && ((psWidget->ui32Highlight == FIELD_OK) ||
                                    (psWidget->ui32Highlight == FIELD_CANCEL)))
      {
          //
          // Call the callback function and pass the flag to indicate if OK
          // was selected (otherwise it was CANCEL).
          //
          psWidget->pfnOnOkClick(&psWidget->sBase, bOk);
  
          //
          // Set the default highlighted field.  This is the field that will
          // be highlighted the next time this widget is activated.
          //
          psWidget->ui32Highlight = FIELD_CANCEL;
  
          //
          // Return to caller, indicating the button event was handled.
          //
          return(1);
      }
      else
      {
          //
          // There is no callback function, or neither the OK or CANCEL fields is
          // highlighted.  In this case ingore the button event.
          //
          return(0);
      }
  }
  
  //*****************************************************************************
  //
  //! Dispatch button events destined for this widget.
  //!
  //! \param psWidget is a pointer to the clock setting widget on which to
  //! operate.
  //! \param ui32Msg is the widget message to process.
  //!
  //! This function receives button/key event messages that are meant for
  //! this widget.  It then calls the appropriate function to handle the
  //! button event.
  //!
  //! \return Returns non-zero if the button event was handled, and 0 if the
  //! button event was not handled.
  //
  //*****************************************************************************
  static int32_t
  ClockSetKeyHandler(tWidget *psWidget, uint32_t ui32Msg)
  {
      tClockSetWidget *psClockWidget;
  
      ASSERT(psWidget);
  
      //
      // Get pointer to the clock setting widget.
      //
      psClockWidget = (tClockSetWidget *)psWidget;
  
      //
      // Process the key event
      //
      switch(ui32Msg)
      {
          //
          // Select key
          //
          case WIDGET_MSG_KEY_SELECT:
          {
              return(ClockSetKeySelect(psClockWidget));
          }
  
          //
          // Up button
          //
          case WIDGET_MSG_KEY_UP:
          {
              return(ClockSetKeyUp(psClockWidget));
          }
  
          //
          // Down button
          //
          case WIDGET_MSG_KEY_DOWN:
          {
              return(ClockSetKeyDown(psClockWidget));
          }
  
          //
          // Left button
          //
          case WIDGET_MSG_KEY_LEFT:
          {
              return(ClockSetKeyLeft(psClockWidget));
          }
  
          //
          // Right button
          //
          case WIDGET_MSG_KEY_RIGHT:
          {
              return(ClockSetKeyRight(psClockWidget));
          }
  
          //
          // This is an unexpected event.  Return an indication that the event
          // was not handled.
          //
          default:
          {
              return(0);
          }
      }
  }
  
  //*****************************************************************************
  //
  //! Handles messages for a clock setting  widget.
  //!
  //! \param psWidget is a pointer to the clock set widget.
  //! \param ui32Msg is the message.
  //! \param ui32Param1 is the first parameter to the message.
  //! \param ui32Param2 is the second parameter to the message.
  //!
  //! This function receives messages intended for this clock set widget and
  //! processes them accordingly.  The processing of the message varies based on
  //! the message in question.
  //!
  //! Unrecognized messages are handled by calling WidgetDefaultMsgProc().
  //!
  //! \return Returns a value appropriate to the supplied message.
  //
  //*****************************************************************************
  int32_t
  ClockSetMsgProc(tWidget *psWidget, uint32_t ui32Msg, uint32_t ui32Param1,
                  uint32_t ui32Param2)
  {
      //
      // Check the arguments.
      //
      ASSERT(psWidget);
  
      //
      // Determine which message is being sent.
      //
      switch(ui32Msg)
      {
          //
          // The widget paint request has been sent.
          //
          case WIDGET_MSG_PAINT:
          {
              //
              // Handle the widget paint request.
              //
              ClockSetPaint(psWidget);
  
              //
              // Return one to indicate that the message was successfully
              // processed.
              //
              return(1);
          }
  
          //
          // Process any button/key event messages.
          //
          case WIDGET_MSG_KEY_SELECT:
          case WIDGET_MSG_KEY_UP:
          case WIDGET_MSG_KEY_DOWN:
          case WIDGET_MSG_KEY_LEFT:
          case WIDGET_MSG_KEY_RIGHT:
          {
              //
              // If the key event is for this widget, then process the key event
              //
              if((tWidget *)ui32Param1 == psWidget)
              {
                  return(ClockSetKeyHandler(psWidget, ui32Msg));
              }
          }
  
          //
          // An unknown request has been sent.
          //
          default:
          {
              //
              // Let the default message handler process this message.
              //
              return(WidgetDefaultMsgProc(psWidget, ui32Msg, ui32Param1,
                                          ui32Param2));
          }
      }
  }
  
  //*****************************************************************************
  //
  //! Initializes a clock setting widget.
  //!
  //! \param psWidget is a pointer to the clock set widget to initialize.
  //! \param psDisplay is a pointer to the display on which to draw the widget.
  //! \param i32X is the X coordinate of the upper left corner of the widget.
  //! \param i32Y is the Y coordinate of the upper left corner of the widget.
  //! \param i32Width is the width of the widget.
  //! \param i32Height is the height of the widget.
  //! \param psFont is the font to use for drawing text on the widget.
  //! \param ui32ForegroundColor is the color of the text and lines on the
  //! widget.
  //! \param ui32BackgroundColor is the color of the widget background.
  //! \param psTime is a pointer to the time structure to use for clock fields.
  //! \param pfnOnOkClick is a callback function that is called when the user
  //! selects the OK field on the display.
  //!
  //! This function initializes the caller provided clock setting widget.
  //!
  //! \return None.
  //
  //*****************************************************************************
  void
  ClockSetInit(tClockSetWidget *psWidget, const tDisplay *psDisplay,
               int32_t i32X, int32_t i32Y, int32_t i32Width, int32_t i32Height,
               tFont *psFont, uint32_t ui32ForegroundColor,
               uint32_t ui32BackgroundColor, struct tm *psTime,
               void (*pfnOnOkClick)(tWidget *psWidget, bool bOk))
  {
      uint32_t ui32Idx;
  
      //
      // Check the arguments.
      //
      ASSERT(psWidget);
      ASSERT(psDisplay);
  
      //
      // Clear out the widget structure.
      //
      for(ui32Idx = 0; ui32Idx < sizeof(tClockSetWidget); ui32Idx += 4)
      {
          ((uint32_t *)psWidget)[ui32Idx / 4] = 0;
      }
  
      //
      // Set the size of the widget structure.
      //
      psWidget->sBase.i32Size = sizeof(tClockSetWidget);
  
      //
      // Mark this widget as fully disconnected.
      //
      psWidget->sBase.psParent = 0;
      psWidget->sBase.psNext = 0;
      psWidget->sBase.psChild = 0;
  
      //
      // Save the display pointer.
      //
      psWidget->sBase.psDisplay = psDisplay;
  
      //
      // Set the extents of the display area.
      //
      psWidget->sBase.sPosition.i16XMin = i32X;
      psWidget->sBase.sPosition.i16YMin = i32Y;
      psWidget->sBase.sPosition.i16XMax = i32X + i32Width - 1;
      psWidget->sBase.sPosition.i16YMax = i32Y + i32Height - 1;
  
      //
      // Initialize the widget fields
      //
      psWidget->psFont = psFont;
      psWidget->ui32ForegroundColor = ui32ForegroundColor;
      psWidget->ui32BackgroundColor = ui32BackgroundColor;
      psWidget->psTime = psTime;
      psWidget->pfnOnOkClick = pfnOnOkClick;
  
      //
      // Use the clock set message handler to process messages to this widget.
      //
      psWidget->sBase.pfnMsgProc = ClockSetMsgProc;
  }
  
  //*****************************************************************************
  //
  // Close the Doxygen group.
  //! @}
  //
  //*****************************************************************************
  
  