/*********************************************************************
*                    SEGGER Microcontroller GmbH                     *
*        Solutions for real time microcontroller applications        *
**********************************************************************
*                                                                    *
*        (c) 1996 - 2022  SEGGER Microcontroller GmbH                *
*                                                                    *
*        Internet: www.segger.com    Support:  support@segger.com    *
*                                                                    *
**********************************************************************

** emWin V6.26 - Graphical user interface for embedded applications **
emWin is protected by international copyright laws.   Knowledge of the
source code may not be used to write a similar product.  This file may
only  be used  in accordance  with  a license  and should  not be  re-
distributed in any way. We appreciate your understanding and fairness.
----------------------------------------------------------------------
File        : EDIT_Custom_KeyHandler.c
Purpose     : This sample demonstrates how a custom key handler can be
              set to an EDIT widget. In this example, the input of the
              EDIT is checked to be a valid IP address.
Requirements: WindowManager - (x)
              MemoryDevices - ( )
              AntiAliasing  - ( )
              VNC-Server    - ( )
              PNG-Library   - ( )
              TrueTypeFonts - ( )
Wiki link   : https://wiki.segger.com/EDIT_Custom_KeyHandler_%28Sample%29
---------------------------END-OF-HEADER------------------------------
*/

#include "DIALOG.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/
/*********************************************************************
*
*       _IsNumber
*/
static U8 _IsNumber(char c) {
  return ((c >= '0') && (c <= '9')) ? 1 : 0;
}

/*********************************************************************
*
*       _AddKey
*/
static void _AddKey(EDIT_Handle hObj, int Key) {
  char * pBuffer;
  int    NumChars;
  int    NumBytes;
  int    i;
  int    NumDots;
  char   Prev;
  int    LastDot;
  char * pNumber;
  int    Num;

  //
  // We want the default behavior for these keys.
  //
  switch (Key) {
  case GUI_KEY_HOME:
  case GUI_KEY_END:
  case GUI_KEY_LEFT:
  case GUI_KEY_RIGHT:
  case GUI_KEY_BACKSPACE:
    //
    // Key handler has to be temporarily NULLed to prevent an endless recursion.
    //
    EDIT_SetpfAddKeyEx(hObj, 0);
    EDIT_AddKey(hObj, Key);
    EDIT_SetpfAddKeyEx(hObj, _AddKey);
    return;
  }
  //
  // We want to skip all other keys that are not numbers or dots.
  // 
  if (!((_IsNumber(Key)) || (Key == '.'))) {
    return;
  }
  //
  // Check if limit has been reached.
  //
  NumChars = EDIT_GetNumChars(hObj);
  if (NumChars == 15) {
    return;
  }
  //
  // Alloc buffer with a little extra space and retrieve the current EDIT text.
  //
  NumBytes = NumChars + 6;
  pBuffer  = (char *)malloc(NumBytes);
  EDIT_GetText(hObj, pBuffer, NumBytes);
  //
  // Count the dots to see if the limit has been reached
  //
  i = NumDots = 0;
  LastDot = 0;
  while (*(pBuffer + i)) {
    if (*(pBuffer + i) == '.') {
      NumDots++;
      LastDot = i;
    }
    i++;
  }
  //
  // If last number has 3 digits
  //
  if ((NumDots == 3) && (LastDot == (NumChars - 4))) {
    free(pBuffer);
    return;
  }
  //
  // Check if maximum number of dots has been reached.
  // 
  if (Key == '.') {
    if (NumDots == 3) {
      free(pBuffer);
      return;
    }
  }
  //
  // Add dot if previous character is a number
  // 
  if (Key == '.') {
    Prev = *(pBuffer + (NumChars - 1));
    if ((Prev != '.') && (_IsNumber(Prev))) {
      *(pBuffer + NumChars++) = Key;
    }
  }
  //
  // Add number
  //
  if (_IsNumber(Key)) {
    *(pBuffer + NumChars++) = Key;
  }
  //
  // Zero-terminate string
  //
  *(pBuffer + NumChars) = 0;
  //
  // Get position of last dot
  //
  i = NumChars;
  LastDot = -1;
  do {
    if (*(pBuffer + i) == '.') {
      LastDot = i;
      break;
    }
    i--;
  } while (i > 0);
  pNumber = pBuffer;
  if (LastDot != -1) {
    pNumber += LastDot + 1;
  }
  Num = atoi(pNumber);
  if (Num > 255) {
    memcpy(pNumber, "255",  4);
  }
  //
  // Add dot if necessary.
  //
  if ((Num > 100) && (NumDots < 3)) {
    strcat(pNumber, ".");
    NumChars++;
  }
  //
  // Copy the new text buffer to the EDIT and free it
  //
  EDIT_SetText(hObj, (const char *)pBuffer);
  free(pBuffer);
  //
  // Update cursor position
  //
  EDIT_SetCursorAtChar(hObj, NumChars);
}

/*********************************************************************
*
*       _cbBk
*/
static void _cbBk(WM_MESSAGE * pMsg) {
  switch (pMsg->MsgId) {
  case WM_PAINT:
    GUI_SetBkColor(GUI_WHITE);
    GUI_Clear();
    GUI_SetColor(GUI_BLACK);
    GUI_SetFont(&GUI_Font16_1);
    GUI_DispStringAt("Enter IP address:", 10, 10);
    break;
  default:
    WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {
  WM_HWIN hEdit;
  WM_HWIN hKeyboard;

  //
  // Init GUI
  //
  GUI_Init();
  WM_SetCallback(WM_HBKWIN, _cbBk);
  //
  // Create EDIT widget
  //
  hEdit = EDIT_CreateEx(10, 30, 100, 25, WM_HBKWIN, WM_CF_SHOW, 0, GUI_ID_EDIT0, 100);
  //
  // Set custom key handling function
  //
  EDIT_SetpfAddKeyEx(hEdit, _AddKey);
  //
  // Create numpad for entering
  //
  hKeyboard = KEYBOARD_CreateUser(150, 10, 150, 200, WM_HBKWIN, WM_CF_SHOW, 0, &KEYBOARD_NUMPAD, GUI_ID_KEYBOARD0, 0);

  while (1) {
    GUI_Delay(100);
  }
}

/*************************** End of file ****************************/
