/*********************************************************************
*                    SEGGER Microcontroller GmbH                     *
*        Solutions for real time microcontroller applications        *
**********************************************************************
*                                                                    *
*        (c) 1996 - 2019  SEGGER Microcontroller GmbH                *
*                                                                    *
*        Internet: www.segger.com    Support:  support@segger.com    *
*                                                                    *
**********************************************************************

** emWin V5.50 - 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        : WIDGET_EffectVGA.c
Purpose     : Example demonstrating the use of widget effects
Requirements: WindowManager - (x)
              MemoryDevices - (x)
              AntiAliasing  - ( )
              VNC-Server    - ( )
              PNG-Library   - ( )
              TrueTypeFonts - ( )
----------------------------------------------------------------------
*/

#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "GUI.h"
#include "DIALOG.h"
#include "PROGBAR.h"
#include "LISTVIEW.h"
#include "GRAPH.h"
#include "MULTIPAGE.h"
#include "MENU.h"
#include "LCDConf.h"
#include "GUIConf.h"

#if !defined(WIDGET_USE_SCHEME_MEDIUM)
  #error Wrong scheme selected!
#endif

/*********************************************************************
*
*       Defines
*
**********************************************************************
*/
#define NUM_WIDGETS GUI_COUNTOF(_aID)
#define ID_MENU             (GUI_ID_USER +  0)
#define ID_MENU_FILE_NEW    (GUI_ID_USER +  1)
#define ID_MENU_FILE_OPEN   (GUI_ID_USER +  2)
#define ID_MENU_FILE_CLOSE  (GUI_ID_USER +  3)
#define ID_MENU_FILE_EXIT   (GUI_ID_USER +  4)
#define ID_MENU_FILE_RECENT (GUI_ID_USER +  5)
#define ID_MENU_RECENT_0    (GUI_ID_USER +  6)
#define ID_MENU_RECENT_1    (GUI_ID_USER +  7)
#define ID_MENU_RECENT_2    (GUI_ID_USER +  8)
#define ID_MENU_RECENT_3    (GUI_ID_USER +  9)
#define ID_MENU_EDIT_UNDO   (GUI_ID_USER + 10)
#define ID_MENU_EDIT_REDO   (GUI_ID_USER + 11)
#define ID_MENU_EDIT_COPY   (GUI_ID_USER + 12)
#define ID_MENU_EDIT_PASTE  (GUI_ID_USER + 13)
#define ID_MENU_EDIT_DELETE (GUI_ID_USER + 14)
#define ID_MENU_HELP_ABOUT  (GUI_ID_USER + 15)

//
// Recommended memory to run the sample with adequate performance
//
#define RECOMMENDED_MEMORY (1024L * 60)

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
//
// Dialog resource of main dialog box
//
static const GUI_WIDGET_CREATE_INFO _aDlgWidgets[] = {
  { WINDOW_CreateIndirect,    "",             0,                    0,   0, 690, 435, 0},
  { TEXT_CreateIndirect,      "Progress bar",  GUI_ID_TEXT0,       10,  35, 120,  25, TEXT_CF_HCENTER},
  { PROGBAR_CreateIndirect,   NULL,            GUI_ID_PROGBAR0,    10,  60, 120,  25 },
  { TEXT_CreateIndirect,      "Button",        GUI_ID_TEXT0,       10,  90, 120,  25, TEXT_CF_HCENTER},
  { BUTTON_CreateIndirect,    "Button",        GUI_ID_BUTTON0,     10, 115, 120,  25 },
  { TEXT_CreateIndirect,      "Dropdown",      GUI_ID_TEXT0,       10, 145, 120,  25, TEXT_CF_HCENTER},
  { DROPDOWN_CreateIndirect,  NULL,            GUI_ID_DROPDOWN0,   10, 170, 120,  85, DROPDOWN_CF_AUTOSCROLLBAR},
  { TEXT_CreateIndirect,      "Edit",          GUI_ID_TEXT0,      150,  35, 120,  25, TEXT_CF_HCENTER},
  { EDIT_CreateIndirect,      NULL,            GUI_ID_EDIT0,      150,  60, 120,  25 },
  { TEXT_CreateIndirect,      "Listbox",       GUI_ID_TEXT0,      150,  90, 120,  25, TEXT_CF_HCENTER},
  { LISTBOX_CreateIndirect,   "",              GUI_ID_LISTBOX0,   150, 115, 120, 165, 0, 0 },
  { TEXT_CreateIndirect,      "Listview",      GUI_ID_TEXT0,      290,  35, 150,  25, TEXT_CF_HCENTER},
  { LISTVIEW_CreateIndirect,  NULL,            GUI_ID_LISTVIEW0,  290,  60, 150, 135, 0 },
  { TEXT_CreateIndirect,      "Multiedit",     GUI_ID_TEXT0,      290, 200, 150,  25, TEXT_CF_HCENTER},
  { MULTIEDIT_CreateIndirect, "",              GUI_ID_MULTIEDIT0, 290, 225, 150,  60, 0, 0 },
  { TEXT_CreateIndirect,      "Scrollbars",    GUI_ID_TEXT0,      460,  35, 100,  25, TEXT_CF_HCENTER},
  { SCROLLBAR_CreateIndirect, NULL,            GUI_ID_SCROLLBAR1, 460,  60,  20, 200, SCROLLBAR_CF_VERTICAL },
  { SCROLLBAR_CreateIndirect, NULL,            GUI_ID_SCROLLBAR2, 490,  60,  70, 200, SCROLLBAR_CF_VERTICAL },
  { SCROLLBAR_CreateIndirect, NULL,            GUI_ID_SCROLLBAR0, 460, 270, 100,  15, 0 },
  { TEXT_CreateIndirect,      "Sliders",       GUI_ID_TEXT0,      580,  35, 100,  25, TEXT_CF_HCENTER},
  { SLIDER_CreateIndirect,    NULL,            GUI_ID_SLIDER1,    580,  60,  20, 200, SLIDER_CF_VERTICAL },
  { SLIDER_CreateIndirect,    NULL,            GUI_ID_SLIDER2,    610,  60,  70, 200, SLIDER_CF_VERTICAL },
  { SLIDER_CreateIndirect,    NULL,            GUI_ID_SLIDER0,    580, 270, 100,  15, 0 },
  { TEXT_CreateIndirect,      "Graph",         GUI_ID_TEXT0,      210, 300, 175,  25, TEXT_CF_HCENTER},
  { GRAPH_CreateIndirect,     0,               GUI_ID_GRAPH0,     210, 325, 175, 100 },
  { TEXT_CreateIndirect,      "Multipage",     GUI_ID_TEXT0,      400, 300, 220,  25, TEXT_CF_HCENTER},
  { MULTIPAGE_CreateIndirect, "Multipage",     GUI_ID_MULTIPAGE0, 400, 325, 220, 100 },
};
//
// Dialog resource of options dialog box
//
static const GUI_WIDGET_CREATE_INFO _aDlgOptions[] = {
  { FRAMEWIN_CreateIndirect,  "Effect", 0,                  10, 325, 185, 120,   0},
  { CHECKBOX_CreateIndirect,  NULL,     GUI_ID_CHECK0,       0,   2,  90,   0 },
  { RADIO_CreateIndirect,     NULL,     GUI_ID_RADIO0,      80,   2,  95, 100,   0,  0x1e03 },
};
//
// Dialog resource of first multipage window
//
static const GUI_WIDGET_CREATE_INFO _aDialogCreate1[] = {
  { WINDOW_CreateIndirect,    "Dialog 1", 0,                   0,   0, 260, 100  },
  { TEXT_CreateIndirect,      "Dialog 1", 0,                   5,   5,  80,  25, TEXT_CF_LEFT },
  { BUTTON_CreateIndirect,    "Button",   GUI_ID_BUTTON0,      5,  30,  80,  25, 0},
};
//
// Dialog resource of second multipage window
//
static const GUI_WIDGET_CREATE_INFO _aDialogCreate2[] = {
  { WINDOW_CreateIndirect,    "Dialog 2", 0,                   0,   0, 260, 100, },
  { TEXT_CreateIndirect,      "Dialog 2", 0,                   5,   5,  80,  25, TEXT_CF_LEFT },
  { SLIDER_CreateIndirect,    "",         GUI_ID_SLIDER0,      5,  30, 200,  40  },
};
//
// Array of widget ID's
//
static int _aID[] = { GUI_ID_BUTTON0,    GUI_ID_EDIT0,      GUI_ID_LISTBOX0,   GUI_ID_PROGBAR0,   
                      GUI_ID_LISTVIEW0,  GUI_ID_MULTIEDIT0, GUI_ID_DROPDOWN0,  GUI_ID_SCROLLBAR0, 
                      GUI_ID_SCROLLBAR1, GUI_ID_SCROLLBAR2, GUI_ID_SLIDER0,    GUI_ID_SLIDER1,    
                      GUI_ID_SLIDER2,    GUI_ID_GRAPH0,     GUI_ID_MULTIPAGE0};
//
// Array of widget handles
//
static WM_HWIN _ahWin[GUI_COUNTOF(_aID)];
//
// Makes it easier to access the array _ahWin
//
enum { BUTTON0,    EDIT0,      LISTBOX0,   PROGBAR0, 
       LISTVIEW0,  MULTIEDIT0, DROPDOWN0,  SCROLLBAR0, 
       SCROLLBAR1, SCROLLBAR2, SLIDER0,    SLIDER1,    
       SLIDER2,    GRAPH0,     MULTIPAGE0};
//
// Array of available effects
//
const WIDGET_EFFECT * _apEffect[] = {&WIDGET_Effect_3D,     
                                     &WIDGET_Effect_Simple, 
                                     &WIDGET_Effect_None};
//
// Array of strings used to label the frame window
//
const char *   _apEffects[] = {"Widget effect: 3D",
                               "Widget effect: Simple", 
                               "Widget effect: None"};
//
// Used for graph widget
//
static I16 _aValue[3];                                            // Array of values to be added
static GRAPH_DATA_Handle  _ahData[3];                             // Array of handles for the GRAPH_DATA objects
static GUI_COLOR _aColor[] = {GUI_RED, GUI_GREEN, GUI_LIGHTBLUE}; // Array of colors for the GRAPH_DATA objects

static WM_HWIN _hDlg;
static WM_HWIN _hFrameWin;
static int     _AutoMode = 1;

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/
/*********************************************************************
*
*       _AddValues
*
* Function description
*   This routine calculates new random values in dependence of the previous added values
*   and adds them to the GRAPH_DATA objects
*/
static void _AddValues(int MaxValue) {
  unsigned i;

  for (i = 0; i < GUI_COUNTOF(_aValue); i++) {
    int Add = rand() % (2 + i * i);
    int Vz  = ((rand() % 2) << 1) - 1;
    _aValue[i] += Add * Vz;
    if (_aValue[i] > MaxValue) {
      _aValue[i] = MaxValue;
    } else if (_aValue[i] < 0) {
      _aValue[i] = 0;
    }
    GRAPH_DATA_YT_AddValue(_ahData[i], _aValue[i]);
  }
}

/*********************************************************************
*
*       _SetWidgetEffect
*
* Function description
*   Sets the effect for the given widget and recursive for its child windows
*/
static void _SetWidgetEffect(WM_HWIN hWin, const WIDGET_EFFECT * pEffect) {
  WM_HWIN hChild;

  if (hWin) {
    WIDGET_SetEffect(hWin, pEffect); // Set effect for the widget
    //
    // Iterate over the child windows
    //
    hChild = WM_GetFirstChild(hWin);
    while (hChild) {
      _SetWidgetEffect(hChild, pEffect); // Set effect for the child windows
      hChild = WM_GetNextSibling(hChild);
    }
  }
}

/*********************************************************************
*
*       _SetEffect
*/
static void _SetEffect(int Index) {
  unsigned              i;
  const WIDGET_EFFECT * pEffect;

  pEffect = _apEffect[Index];
  WIDGET_SetDefaultEffect(pEffect);
  FRAMEWIN_SetText(_hFrameWin, _apEffects[Index]);
  //
  // Iterate over all dialog widgets
  //
  for (i = 0; i < NUM_WIDGETS; i++) {
    _SetWidgetEffect(_ahWin[i], _apEffect[Index]); // Set effect
  }
}

/*********************************************************************
*
*       _AddMenuItem
*/
static void _AddMenuItem(MENU_Handle hMenu, MENU_Handle hSubmenu, const char* pText, U16 Id, U16 Flags) {
  MENU_ITEM_DATA Item;

  Item.pText    = pText;
  Item.hSubmenu = hSubmenu;
  Item.Flags    = Flags;
  Item.Id       = Id;
  MENU_AddItem(hMenu, &Item);
}

/*********************************************************************
*
*       _CreateMenu
*/
static WM_HWIN _CreateMenu(WM_HWIN hParent) {
  MENU_Handle hMenu;
  MENU_Handle hMenuFile;
  MENU_Handle hMenuEdit;
  MENU_Handle hMenuHelp;
  MENU_Handle hMenuRecent;

  //
  // Create main menu
  //
  hMenu       = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_HORIZONTAL, ID_MENU);
  // Create sub menus
  hMenuFile   = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_VERTICAL, 0);
  hMenuEdit   = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_VERTICAL, 0);
  hMenuHelp   = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_VERTICAL, 0);
  hMenuRecent = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_VERTICAL, 0);
  //
  // Add menu items to menu 'Recent'
  //
  _AddMenuItem(hMenuRecent, 0,           "File 0",   ID_MENU_RECENT_0,    0);
  _AddMenuItem(hMenuRecent, 0,           "File 1",   ID_MENU_RECENT_1,    0);
  _AddMenuItem(hMenuRecent, 0,           "File 2",   ID_MENU_RECENT_2,    0);
  _AddMenuItem(hMenuRecent, 0,           "File 3",   ID_MENU_RECENT_3,    0);
  //
  // Add menu items to menu 'File'
  //
  _AddMenuItem(hMenuFile,   0,           "New",      ID_MENU_FILE_NEW,    0);
  _AddMenuItem(hMenuFile,   0,           "Open",     ID_MENU_FILE_OPEN,   0);
  _AddMenuItem(hMenuFile,   0,           "Close",    ID_MENU_FILE_CLOSE,  0);
  _AddMenuItem(hMenuFile,   0,           0,          0,                   MENU_IF_SEPARATOR);
  _AddMenuItem(hMenuFile,   hMenuRecent, "Files...", ID_MENU_FILE_RECENT, 0);
  _AddMenuItem(hMenuFile,   0,           0,          0,                   MENU_IF_SEPARATOR);
  _AddMenuItem(hMenuFile,   0,           "Exit",     ID_MENU_FILE_EXIT,   0);
  //
  // Add menu items to menu 'Edit'
  //
  _AddMenuItem(hMenuEdit,   0,           "Undo",     ID_MENU_EDIT_UNDO,   0);
  _AddMenuItem(hMenuEdit,   0,           "Redo",     ID_MENU_EDIT_REDO,   0);
  _AddMenuItem(hMenuEdit,   0,           0,          0,                   MENU_IF_SEPARATOR);
  _AddMenuItem(hMenuEdit,   0,           "Copy",     ID_MENU_EDIT_COPY,   0);
  _AddMenuItem(hMenuEdit,   0,           "Paste",    ID_MENU_EDIT_PASTE,  0);
  _AddMenuItem(hMenuEdit,   0,           "Delete",   ID_MENU_EDIT_DELETE, 0);
  //
  // Add menu items to menu 'Help'
  //
  _AddMenuItem(hMenuHelp,   0,           "About",    ID_MENU_HELP_ABOUT,  0);
  //
  // Add menu items to main menu
  //
  _AddMenuItem(hMenu,       hMenuFile,   "File",     0,                   0);
  _AddMenuItem(hMenu,       hMenuEdit,   "Edit",     0,                   0);
  _AddMenuItem(hMenu,       hMenuHelp,   "Help",     0,                   0);
  //
  // Attach menu to parent window
  //
  MENU_Attach(hMenu, hParent, 0, 0, WM_GetWindowSizeX(hParent), 0, 0);
  return hMenu;
}

/*********************************************************************
*
*       _cbBkWindow
*/
static void _cbBkWindow(WM_MESSAGE * pMsg) {
  switch (pMsg->MsgId) {
  case WM_PAINT:
    GUI_SetBkColor(GUI_BLUE);
    GUI_Clear();
    GUI_SetColor(GUI_WHITE);
    GUI_SetFont(&GUI_Font24_ASCII);
    GUI_DispStringHCenterAt("WIDGET_Effect - Sample", 160, 5);
    break;
  default:
    WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       _cbDialogPage
*
* Function description
*   Dialog routine for multi page windows
*/
static void _cbDialogPage(WM_MESSAGE * pMsg) {
  WM_DefaultProc(pMsg);
}

/*********************************************************************
*
*       _cbCallbackWidgets
*
* Function description
*   Initializes the widgets of the main dialog box
*/
static void _cbCallbackWidgets(WM_MESSAGE * pMsg) {
  GRAPH_SCALE_Handle hScaleH;
  GRAPH_SCALE_Handle hScaleV;
  WM_HWIN            hDlg;
  unsigned           i;

  hDlg = pMsg->hWin;
  switch (pMsg->MsgId) {
    case WM_INIT_DIALOG:
      //
      // Get handles of widgets
      //
      for (i = 0; i < NUM_WIDGETS; i++) {
        _ahWin[i] = WM_GetDialogItem(hDlg, _aID[i]);
      }
      //
      // Init dropdown widget
      //
      for (i = 0; i < 8; i++) {
        char acBuffer[] = {"Item x"};
        int Len = strlen(acBuffer);
        acBuffer[Len - 1] = '1' + i;
        DROPDOWN_AddString(_ahWin[DROPDOWN0], acBuffer);
      }
      //
      // Init edit widget
      //
      EDIT_SetText(_ahWin[EDIT0], "Edit");
      //
      // Init listbox widget
      //
      LISTBOX_SetAutoScrollV(_ahWin[LISTBOX0], 1);
      for (i = 0; i < 4; i++) {
        char acBuffer[] = {"Item x"};
        int Len = strlen(acBuffer);
        acBuffer[Len - 1] = '1' + i;
        LISTBOX_AddString(_ahWin[LISTBOX0], acBuffer);
      }
      //
      // Init listview widget
      //
      for (i = 0; i < 2; i++) {
        char acBuffer[] = {"Col. x"};
        int Len = strlen(acBuffer);
        acBuffer[Len - 1] = '1' + i;
        LISTVIEW_AddColumn(_ahWin[LISTVIEW0], 60, acBuffer, GUI_TA_CENTER);
      }
      for (i = 0; i < 9; i++) {
        int j;
        LISTVIEW_AddRow(_ahWin[LISTVIEW0], NULL);
        for (j = 0; j < (int)LISTVIEW_GetNumColumns(_ahWin[LISTVIEW0]); j++) {
          char acBuffer[] = {"Rx/Cx"};
          acBuffer[1] = '1' + i;
          acBuffer[4] = '1' + j;
          LISTVIEW_SetItemText(_ahWin[LISTVIEW0], j, i, acBuffer);
        }
      }
      LISTVIEW_SetGridVis(_ahWin[LISTVIEW0], 1);
      SCROLLBAR_CreateAttached(_ahWin[LISTVIEW0], SCROLLBAR_CF_VERTICAL);
      //
      // Init multiedit widget
      //
      MULTIEDIT_SetText(_ahWin[MULTIEDIT0], "This text could be modified by the MULTIEDIT widget");
      MULTIEDIT_SetWrapWord(_ahWin[MULTIEDIT0]);
      MULTIEDIT_SetAutoScrollV(_ahWin[MULTIEDIT0], 1);
      //
      // Init progbar widget
      //
      WIDGET_SetEffect(_ahWin[PROGBAR0], &WIDGET_Effect_3D);
      //
      // Init graph widget
      //
      for (i = 0; i < GUI_COUNTOF(_aColor); i++) {
        _aValue[i] = rand() % 95;
        _ahData[i] = GRAPH_DATA_YT_Create(_aColor[i], 500, 0, 0);
        GRAPH_AttachData(_ahWin[GRAPH0], _ahData[i]);
      }
      GRAPH_SetGridDistY(_ahWin[GRAPH0], 25);
      GRAPH_SetGridVis(_ahWin[GRAPH0], 1);
      GRAPH_SetGridFixedX(_ahWin[GRAPH0], 1);
      GRAPH_SetBorder(_ahWin[GRAPH0], 20, 4, 5, 4);
      //
      // Create and add vertical scale of graph widget
      //
      hScaleV = GRAPH_SCALE_Create(18, GUI_TA_RIGHT, GRAPH_SCALE_CF_VERTICAL, 25);
      GRAPH_SCALE_SetTextColor(hScaleV, GUI_RED);
      GRAPH_AttachScale(_ahWin[GRAPH0], hScaleV);
      //
      // Create and add horizontal scale of graph widget
      //
      hScaleH = GRAPH_SCALE_Create(46, GUI_TA_HCENTER | GUI_TA_VCENTER, GRAPH_SCALE_CF_HORIZONTAL, 50);
      GRAPH_SCALE_SetTextColor(hScaleH, GUI_DARKGREEN);
      GRAPH_AttachScale(_ahWin[GRAPH0], hScaleH);
      //
      // Init multipage widget
      //
      MULTIPAGE_AddPage(_ahWin[MULTIPAGE0],
                        GUI_CreateDialogBox(_aDialogCreate1, GUI_COUNTOF(_aDialogCreate1), _cbDialogPage, WM_UNATTACHED, 0, 0), 
                        "Page 1");
      MULTIPAGE_AddPage(_ahWin[MULTIPAGE0],
                        GUI_CreateDialogBox(_aDialogCreate2, GUI_COUNTOF(_aDialogCreate2), _cbDialogPage, WM_UNATTACHED, 0, 0), 
                        "Page 2");
      //
      // Create and attach menu
      //
      _CreateMenu(hDlg);
      break;
    default:
      WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       _cbCallbackFramewin
*
* Function description
*   Handles the scroll messages of the scrollbar
*/
static void _cbCallbackFramewin(WM_MESSAGE * pMsg) {
  WM_HWIN hDlg;

  hDlg = pMsg->hWin;
  switch (pMsg->MsgId) {
    case WM_NOTIFY_PARENT:
      if (pMsg->Data.v == WM_NOTIFICATION_VALUE_CHANGED) {
        if (pMsg->hWinSrc == WM_GetScrollbarH(hDlg)) {
          int xPos, yPos;
          WM_SCROLL_STATE ScrollState;
          WM_GetScrollState(pMsg->hWinSrc, &ScrollState);
          xPos = WM_GetWindowOrgX(WM_GetParent(_hDlg)) - ScrollState.v;
          yPos = WM_GetWindowOrgY(_hDlg);
          WM_MoveTo(_hDlg, xPos, yPos);
        }
      }
      break;
    default:
      WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       _cbCallbackOptions
*
* Function description
*   Callback of the options dialog box, sets the widget effects
*/
static void _cbCallbackOptions(WM_MESSAGE * pMsg) {
  WM_HWIN hDlg;
  WM_HWIN hItem;

  hDlg = pMsg->hWin;
  switch (pMsg->MsgId) {
    case WM_INIT_DIALOG:
      //
      // Init check box
      //
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK0);
      CHECKBOX_Check(hItem);
      CHECKBOX_SetText(hItem, "Auto");
      //
      // Init radio button
      //
      hItem = WM_GetDialogItem(hDlg, GUI_ID_RADIO0);
      RADIO_SetText(hItem, "3D",     0);
      RADIO_SetText(hItem, "Simple", 1);
      RADIO_SetText(hItem, "None",   2);
      break;
    case WM_NOTIFY_PARENT:
      if (pMsg->Data.v == WM_NOTIFICATION_VALUE_CHANGED) {
        hItem = WM_GetDialogItem(hDlg, GUI_ID_RADIO0);
        if (pMsg->hWinSrc == hItem) {
          _SetEffect(RADIO_GetValue(hItem));
        }
      } else if (pMsg->Data.v == WM_NOTIFICATION_RELEASED) {
        hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK0);
        if (pMsg->hWinSrc == hItem) {
          _AutoMode = CHECKBOX_IsChecked(hItem);
        }
      }
      break;
    default:
      WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {
  GUI_RECT RectDlg;
  GUI_RECT RectClient;
  WM_HWIN  hScrollbar;
  WM_HWIN  hDlgOptions;
  int      Cnt;
  int      IndexEffect;
  int      ButtonState;
  int      DropdownState;
  int      ProgbarValue;
  int      ProgbarInc;
  int      SliderValue;
  int      SliderInc;
  int      ScrollbarValue;
  int      ScrollbarInc;
  int      ListViewInc;
  int      ListBoxInc;
  int      MultiEditInc;
  int      Vz;
  const char          * _apEffects[] = {"Widget effect: 3D", "Widget effect: Simple", "Widget effect: None"};

  Cnt            = 0;
  IndexEffect    = 0;
  ButtonState    = 0;
  DropdownState  = 0;
  ProgbarValue   = 0;
  ProgbarInc     = 1;
  SliderValue    = 0;
  SliderInc      = 1;
  ScrollbarValue = 0;
  ScrollbarInc   = 1;
  ListViewInc    = 1;
  ListBoxInc     = 1;
  MultiEditInc   = 1;
  Vz             = 1;
  GUI_Init();
  //
  // Check if recommended memory for the sample is available
  //
  if (GUI_ALLOC_GetNumFreeBytes() < RECOMMENDED_MEMORY) {
    GUI_ErrorOut("Not enough memory available."); 
    return;
  }
  GUI_CURSOR_Show();
  WM_SetCallback(WM_HBKWIN, _cbBkWindow);
  WM_SetCreateFlags(WM_CF_MEMDEV);  // Use memory devices on all windows to avoid flicker
  WM_EnableMemdev(WM_HBKWIN);       // Enable use of memory devices for desktop windows
  //
  // Create framewindow and set its properties
  //
  _hFrameWin = FRAMEWIN_CreateEx(0, 0, 640, 480, 0, WM_CF_SHOW, 0, 0, "", &_cbCallbackFramewin);
  FRAMEWIN_SetMoveable(_hFrameWin, 1);
  FRAMEWIN_SetText(_hFrameWin, _apEffects[0]);
  FRAMEWIN_SetFont(_hFrameWin, &GUI_Font13B_ASCII);
  //
  // Create main dialog window as child from framewindows client window
  //
  _hDlg = GUI_CreateDialogBox(_aDlgWidgets,
                              GUI_COUNTOF(_aDlgWidgets), 
                              &_cbCallbackWidgets, 
                              WM_GetClientWindow(_hFrameWin), 0, 0);
  //
  // Attach scrollbar to framewindows client window and set its properties
  //
  hScrollbar = SCROLLBAR_CreateAttached(WM_GetClientWindow(_hFrameWin), 0);
  WM_GetWindowRectEx(_hDlg, &RectDlg);
  WM_GetClientRectEx(WM_GetClientWindow(_hFrameWin), &RectClient);
  SCROLLBAR_SetNumItems(hScrollbar, RectDlg.x1);
  SCROLLBAR_SetPageSize(hScrollbar, RectClient.x1);
  //
  // Create options dialog with 'stay on top' and 'moveable' attribute
  //
  hDlgOptions = GUI_CreateDialogBox(_aDlgOptions, 
                                    GUI_COUNTOF(_aDlgOptions), 
                                    &_cbCallbackOptions, 
                                    WM_HBKWIN, 0, 0);
  FRAMEWIN_SetMoveable(hDlgOptions, 1);
  WM_SetStayOnTop(hDlgOptions, 1);
  //
  // Main loop for modifying the widgets
  //
  while (1) {
    if (_AutoMode) {
      Cnt++;
      //
      // Modify progbar
      //
      if ((Cnt % 2) == 0) {
        ProgbarValue += ProgbarInc;
        if ((ProgbarValue == 110) || (ProgbarValue == -10)) {
          ProgbarInc *= -1;
        }
        PROGBAR_SetValue(_ahWin[PROGBAR0], ProgbarValue);
      }
      //
      // Modify slider
      //
      if ((Cnt % 2) == 0) {
        int j;

        SliderValue += SliderInc;
        if ((SliderValue == 100) || (SliderValue == 0)) {
          SliderInc *= -1;
        }
        for (j = 0; j < 3; j++) {
          SLIDER_SetValue(_ahWin[SLIDER0 + j], SliderValue);
        }
      }
      //
      // Modify scrollbar
      //
      if ((Cnt % 3) == 0) {
        int j;

        ScrollbarValue += ScrollbarInc;
        if ((ScrollbarValue == 90) || (ScrollbarValue == 0)) {
          ScrollbarInc *= -1;
        }
        for (j = 0; j < 3; j++) {
          SCROLLBAR_SetValue(_ahWin[SCROLLBAR0 + j], ScrollbarValue);
        }
      }
      //
      // Modify multipage
      //
      if ((Cnt % 120) == 0) {
        MULTIPAGE_SelectPage(_ahWin[MULTIPAGE0], MULTIPAGE_GetSelection(_ahWin[MULTIPAGE0]) ^ 1);
      }
      //
      // Modify dropdown
      //
      if ((Cnt % 120) == 0) {
        DropdownState ^= 1;
        if (DropdownState) {
          DROPDOWN_Expand(_ahWin[DROPDOWN0]);
        } else {
          DROPDOWN_Collapse(_ahWin[DROPDOWN0]);
        }
      }
      //
      // Modify button
      //
      if ((Cnt % 40) == 0) {
        ButtonState ^= 1;
        BUTTON_SetPressed(_ahWin[BUTTON0], ButtonState);
      }
      //
      // Modify listbox
      //
      if ((Cnt % 30) == 0) {
        int Sel;

        Sel = LISTBOX_GetSel(_ahWin[LISTBOX0]);
        if (Sel < 0) {
          Sel = 0;
        }
        LISTBOX_SetSel(_ahWin[LISTBOX0], Sel + ListBoxInc);
        Sel = LISTBOX_GetSel(_ahWin[LISTBOX0]);
        if ((Sel == (int)LISTBOX_GetNumItems(_ahWin[LISTBOX0]) - 1) || (Sel == 0)) {
          ListBoxInc *= -1;
        }
      }
      //
      // Modify listview
      //
      if ((Cnt % 50) == 0) {
        int Sel;

        Sel = LISTVIEW_GetSel(_ahWin[LISTVIEW0]);
        if (Sel < 0) {
          Sel = 0;
        }
        LISTVIEW_SetSel(_ahWin[LISTVIEW0], Sel + ListViewInc);
        Sel = LISTVIEW_GetSel(_ahWin[LISTVIEW0]);
        if ((Sel == (int)LISTVIEW_GetNumRows(_ahWin[LISTVIEW0]) - 1) || (Sel == 0)) {
          ListViewInc *= -1;
        }
      }
      //
      // Modify multiedit
      //
      if ((Cnt % 5) == 0) {
        int  Sel;
        int  Len;
        char acBuffer[100];

        MULTIEDIT_SetCursorOffset(_ahWin[MULTIEDIT0], MULTIEDIT_GetCursorCharPos(_ahWin[MULTIEDIT0]) + MultiEditInc);
        MULTIEDIT_GetText(_ahWin[MULTIEDIT0], acBuffer, sizeof(acBuffer));
        Sel = MULTIEDIT_GetCursorCharPos(_ahWin[MULTIEDIT0]);
        Len = strlen(acBuffer);
        if ((Sel == (Len - 1)) || (Sel == 0)) {
          MultiEditInc *= -1;
        }
        if (!DropdownState) {
          WM_SetFocus(_ahWin[MULTIEDIT0]);
        }
      }
      //
      // Modify graph
      //
      _AddValues(95);
      //
      // Move window
      //
      if ((Cnt % 1200) == 0) {
        int             Inc;
        WM_HWIN         hScroll;
        WM_SCROLL_STATE ScrollState;

        hScroll = WM_GetScrollbarH(WM_GetClientWindow(_hFrameWin));
        WM_GetScrollState(hScroll, &ScrollState);
        Inc = (ScrollState.NumItems - ScrollState.PageSize) / 2;
        ScrollState.v += Inc * Vz;
        if ((ScrollState.v >= Inc * 2) || (ScrollState.v <= 0)) {
          Vz *= -1;
        }
        SCROLLBAR_SetValue(hScroll, ScrollState.v);
      }
      //
      // Change effect
      //
      if ((Cnt % 400) == 0) {
        int     Index;
        WM_HWIN hWin;

        IndexEffect++;
        Index = IndexEffect % GUI_COUNTOF(_apEffect);
        _SetEffect(Index);
        hWin = WM_GetDialogItem(hDlgOptions, GUI_ID_RADIO0);
        RADIO_SetValue(hWin, Index);
      }
    }
    //
    // Wait a while
    //
    GUI_Delay(10);
  }
}

/*************************** End of file ****************************/

