text: /*********************************************************************
  *                SEGGER Microcontroller GmbH & Co. KG                *
  *        Solutions for real time microcontroller applications        *
  **********************************************************************
  *                                                                    *
  *        (c) 1996 - 2017  SEGGER Microcontroller GmbH & Co. KG       *
  *                                                                    *
  *        Internet: www.segger.com    Support:  support@segger.com    *
  *                                                                    *
  **********************************************************************
  
  ** emWin V5.46 - Graphical user interface for embedded applications **
  All  Intellectual Property rights  in the Software belongs to  SEGGER.
  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 the following terms:
  
  The software has been licensed to  ARM LIMITED whose registered office
  is situated at  110 Fulbourn Road,  Cambridge CB1 9NJ,  England solely
  for  the  purposes  of  creating  libraries  for  ARM7, ARM9, Cortex-M
  series,  and   Cortex-R4   processor-based  devices,  sublicensed  and
  distributed as part of the  MDK-ARM  Professional  under the terms and
  conditions  of  the   End  User  License  supplied  with  the  MDK-ARM
  Professional. 
  Full source code is available at: www.segger.com
  
  We appreciate your understanding and fairness.
  ----------------------------------------------------------------------
  Licensing information
  Licensor:                 SEGGER Software GmbH
  Licensed to:              ARM Ltd, 110 Fulbourn Road, CB1 9NJ Cambridge, UK
  Licensed SEGGER software: emWin
  License number:           GUI-00181
  License model:            LES-SLA-20007, Agreement, effective since October 1st 2011 
  Licensed product:         MDK-ARM Professional
  Licensed platform:        ARM7/9, Cortex-M/R4
  Licensed number of seats: -
  ----------------------------------------------------------------------
  File        : WIDGET_GraphYT.c
  Purpose     : Demonstrates the use of the GRAPH widget
  Requirements: WindowManager - (x)
                MemoryDevices - ( )
                AntiAliasing  - ( )
                VNC-Server    - ( )
                PNG-Library   - ( )
                TrueTypeFonts - ( )
  ----------------------------------------------------------------------
  */
  #include <stdlib.h>
  #include <string.h>
  
  #include "DIALOG.h"
  #include "GRAPH.h"
  
  /*********************************************************************
  *
  *       Defines
  *
  **********************************************************************
  */
  #define MAX_VALUE 180
  
  //
  // Recommended memory to run the sample with adequate performance
  //
  #define RECOMMENDED_MEMORY (1024L * 30)
  
  /*********************************************************************
  *
  *       Static data
  *
  **********************************************************************
  */
  static GRAPH_DATA_Handle  _ahData[3]; // Array of handles for the GRAPH_DATA objects
  static GRAPH_SCALE_Handle _hScaleV;   // Handle of vertical scale
  static GRAPH_SCALE_Handle _hScaleH;   // Handle of horizontal scale
  
  static I16 _aValue[3];
  static int _Stop = 0;
  
  static GUI_COLOR _aColor[] = {GUI_RED, GUI_GREEN, GUI_LIGHTBLUE}; // Array of colors for the GRAPH_DATA objects
  
  //
  // Dialog ressource
  //
  static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
    { FRAMEWIN_CreateIndirect, "Graph widget demo",  0                ,   0,   0, 320, 240, FRAMEWIN_CF_MOVEABLE },
    { GRAPH_CreateIndirect,     0,                   GUI_ID_GRAPH0    ,   5,   5, 265, 170 },
    { TEXT_CreateIndirect,      "Spacing X:",        0                ,  10, 180,  50,  20 },
    { TEXT_CreateIndirect,      "Spacing Y:",        0                ,  10, 200,  50,  20 },
    { SLIDER_CreateIndirect,    0,                   GUI_ID_SLIDER0   ,  60, 180,  60,  16 },
    { SLIDER_CreateIndirect,    0,                   GUI_ID_SLIDER1   ,  60, 200,  60,  16 },
    { CHECKBOX_CreateIndirect,  0,                   GUI_ID_CHECK0    , 130, 180,  50,   0 },
    { CHECKBOX_CreateIndirect,  0,                   GUI_ID_CHECK1    , 130, 200,  50,   0 },
    { TEXT_CreateIndirect,      "Border",            0                , 275,   5,  35,  15 },
    { CHECKBOX_CreateIndirect,  0,                   GUI_ID_CHECK2    , 275,  20,  35,   0 },
    { CHECKBOX_CreateIndirect,  0,                   GUI_ID_CHECK3    , 275,  40,  35,   0 },
    { CHECKBOX_CreateIndirect,  0,                   GUI_ID_CHECK4    , 275,  60,  35,   0 },
    { CHECKBOX_CreateIndirect,  0,                   GUI_ID_CHECK5    , 275,  80,  35,   0 },
    { TEXT_CreateIndirect,      "Effect",            0                , 275, 100,  35,  15 },
    { RADIO_CreateIndirect,     0,                   GUI_ID_RADIO0    , 270, 115,  35,   0, 0, 3 },
    { CHECKBOX_CreateIndirect,  0,                   GUI_ID_CHECK6    , 180, 180,  50,   0 },
    { CHECKBOX_CreateIndirect,  0,                   GUI_ID_CHECK7    , 180, 200,  50,   0 },
    { BUTTON_CreateIndirect,    "Full Screen",       GUI_ID_BUTTON0   , 240, 180,  65,  18 },
    { CHECKBOX_CreateIndirect,  0,                   GUI_ID_CHECK8    , 240, 200,  70,   0 },
  };
  
  /*********************************************************************
  *
  *       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(void) {
    unsigned i;
  
    for (i = 0; i < GUI_COUNTOF(_aColor); i++) {
      int Add = ((unsigned)rand()) % (2 + i * i);
      int Vz  = (((unsigned)(rand()) % 2) << 1) - 1;
      _aValue[i] += Add * Vz;
      if (_aValue[i] > MAX_VALUE) {
        _aValue[i] = MAX_VALUE;
      } else if (_aValue[i] < 0) {
        _aValue[i] = 0;
      }
      GRAPH_DATA_YT_AddValue(_ahData[i], _aValue[i]);
    }
  }
  
  /*********************************************************************
  *
  *       _UserDraw
  *
  * Function description
  *   This routine is called by the GRAPH object before anything is drawn
  *   and after the last drawing operation.
  */
  static void _UserDraw(WM_HWIN hWin, int Stage) {
    if (Stage == GRAPH_DRAW_LAST) {
      char acText[] = "Temperature";
      GUI_RECT Rect;
      GUI_RECT RectInvalid;
      int FontSizeY;
  
      GUI_SetFont(&GUI_Font13_ASCII);
      FontSizeY = GUI_GetFontSizeY();
      WM_GetInsideRect(&Rect);
      WM_GetInvalidRect(hWin, &RectInvalid);
      Rect.x1 = Rect.x0 + FontSizeY;
      GUI_SetColor(GUI_YELLOW);
      GUI_DispStringInRectEx(acText, &Rect, GUI_TA_HCENTER, strlen(acText), GUI_ROTATE_CCW);
    }
  }
  
  /*********************************************************************
  *
  *       _ForEach
  *
  * Function description
  *   This routine hides/shows all windows except the button, graph and scroll bar widgets
  */
  static void _ForEach(WM_HWIN hWin, void * pData) {
    int Id;
    int FullScreenMode;
  
    FullScreenMode = *(int *)pData;
    Id = WM_GetId(hWin);
    if ((Id == GUI_ID_GRAPH0) || (Id == GUI_ID_BUTTON0) || (Id == GUI_ID_VSCROLL) || (Id == GUI_ID_HSCROLL)) {
      return;
    }
    if (FullScreenMode) {
      WM_HideWindow(hWin);
    } else {
      WM_ShowWindow(hWin);
    }
  }
  
  /*********************************************************************
  *
  *       _ToggleFullScreenMode
  *
  * Function description
  *   This routine switches between full screen mode and normal mode by hiding or showing the
  *   widgets of the dialog, enlarging/shrinking the graph widget and modifying some other
  *   attributes of the dialog widgets.
  */
  static void _ToggleFullScreenMode(WM_HWIN hDlg) {
    static int FullScreenMode;
    static GUI_RECT Rect;
    static unsigned ScalePos;
    WM_HWIN hGraph;
    WM_HWIN hButton;
    WM_HWIN hClient;
    GUI_RECT RectInside;
    int xPos, yPos;
  
    hGraph  = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
    hButton = WM_GetDialogItem(hDlg, GUI_ID_BUTTON0);
    FullScreenMode ^= 1;
    if (FullScreenMode) {       
      //
      // Enter the full screen mode
      //
      hClient = WM_GetClientWindow(hDlg);
      BUTTON_SetText(hButton, "Back");
      WM_MoveWindow(hButton, 0, 11);
      FRAMEWIN_SetTitleVis(hDlg, 0);
      WM_GetInsideRectEx(hClient, &RectInside);
      WM_GetWindowRectEx(hGraph, &Rect);
      WM_ForEachDesc(hClient, _ForEach, &FullScreenMode); // Hide all descendants
      xPos = WM_GetWindowOrgX(hClient);
      yPos = WM_GetWindowOrgY(hClient);
      WM_SetWindowPos(hGraph, xPos, yPos, RectInside.x1, RectInside.y1);
      ScalePos = GRAPH_SCALE_SetPos(_hScaleH, RectInside.y1 - 20);
    } else {
      //
      // Return to normal mode
      //
      BUTTON_SetText(hButton, "Full Screen");
      WM_MoveWindow(hButton, 0, -11);
      WM_ForEachDesc(WM_GetClientWindow(hDlg), _ForEach, &FullScreenMode); // Show all descendants
      WM_SetWindowPos(hGraph, Rect.x0, Rect.y0, Rect.x1 - Rect.x0 + 1, Rect.y1 - Rect.y0 + 1);
      FRAMEWIN_SetTitleVis(hDlg, 1);
      GRAPH_SCALE_SetPos(_hScaleH, ScalePos);
    }
  }
  
  /*********************************************************************
  *
  *       _cbCallback
  *
  * Function description
  *   Callback function of the dialog
  */
  static void _cbCallback(WM_MESSAGE * pMsg) {
    unsigned i;
    int      NCode;
    int      Id;
    int      Value;
    WM_HWIN  hDlg;
    WM_HWIN  hItem;
  
    hDlg = pMsg->hWin;
    switch (pMsg->MsgId) {
    case WM_INIT_DIALOG:
      hItem = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
      //
      // Add graphs
      //
      for (i = 0; i < GUI_COUNTOF(_aColor); i++) {
        _aValue[i] = rand() % 180;
        _ahData[i] = GRAPH_DATA_YT_Create(_aColor[i], 500, 0, 0);
        GRAPH_AttachData(hItem, _ahData[i]);
      }
      //
      // Set graph attributes
      //
      GRAPH_SetGridDistY(hItem, 25);
      GRAPH_SetGridVis(hItem, 1);
      GRAPH_SetGridFixedX(hItem, 1);
      GRAPH_SetUserDraw(hItem, _UserDraw);
      //
      // Create and add vertical scale
      //
      _hScaleV = GRAPH_SCALE_Create( 35, GUI_TA_RIGHT, GRAPH_SCALE_CF_VERTICAL, 25);
      GRAPH_SCALE_SetTextColor(_hScaleV, GUI_YELLOW);
      GRAPH_AttachScale(hItem, _hScaleV);
      //
      // Create and add horizontal scale
      //
      _hScaleH = GRAPH_SCALE_Create(155, GUI_TA_HCENTER, GRAPH_SCALE_CF_HORIZONTAL, 50);
      GRAPH_SCALE_SetTextColor(_hScaleH, GUI_DARKGREEN);
      GRAPH_AttachScale(hItem, _hScaleH);
      //
      // Init check boxes
      //
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK2);
      CHECKBOX_SetText(hItem, "L");
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK3);
      CHECKBOX_SetText(hItem, "T");
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK4);
      CHECKBOX_SetText(hItem, "R");
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK5);
      CHECKBOX_SetText(hItem, "B");
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK0);
      CHECKBOX_SetText(hItem, "Stop");
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK1);
      CHECKBOX_SetText(hItem, "Grid");
      CHECKBOX_SetState(hItem, 1);
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK6);
      CHECKBOX_SetText(hItem, "HScroll");
      CHECKBOX_SetState(hItem, 1);
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK7);
      CHECKBOX_SetText(hItem, "VScroll");
      hItem = WM_GetDialogItem(hDlg, GUI_ID_CHECK8);
      CHECKBOX_SetText(hItem, "MirrorX");
      //
      // Init slider widgets
      //
      hItem = WM_GetDialogItem(hDlg, GUI_ID_SLIDER0);
      SLIDER_SetRange(hItem, 0, 10);
      SLIDER_SetValue(hItem, 5);
      SLIDER_SetNumTicks(hItem, 6);
      hItem = WM_GetDialogItem(hDlg, GUI_ID_SLIDER1);
      SLIDER_SetRange(hItem, 0, 20);
      SLIDER_SetValue(hItem, 5);
      SLIDER_SetNumTicks(hItem, 6);
      //
      // Init radio widget
      //
      hItem = WM_GetDialogItem(hDlg, GUI_ID_RADIO0);
      RADIO_SetText(hItem, "3D", 0);
      RADIO_SetText(hItem, "flat", 1);
      RADIO_SetText(hItem, "-", 2);
      //
      // Init button widget
      //
      hItem = WM_GetDialogItem(hDlg, GUI_ID_BUTTON0);
      WM_SetStayOnTop(hItem, 1);
      break;
    case WM_NOTIFY_PARENT:
      Id    = WM_GetId(pMsg->hWinSrc);      // Id of widget
      NCode = pMsg->Data.v;                 // Notification code
      switch (NCode) {
      case WM_NOTIFICATION_CLICKED:
        switch (Id) {
        case GUI_ID_BUTTON0:
          _ToggleFullScreenMode(hDlg);
          break;
        }
        break;
      case WM_NOTIFICATION_VALUE_CHANGED:
        switch (Id) {
        case GUI_ID_CHECK0:
          //
          // Toggle stop mode
          //
          _Stop ^= 1;
          break;
        case GUI_ID_CHECK1:
          //
          // Toggle grid
          //
          hItem = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
          GRAPH_SetGridVis(hItem, CHECKBOX_IsChecked(WM_GetDialogItem(hDlg, GUI_ID_CHECK1)));
          break;
        case GUI_ID_CHECK2:
        case GUI_ID_CHECK3:
        case GUI_ID_CHECK4:
        case GUI_ID_CHECK5:
          //
          // Toggle border
          //
          hItem = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
          GRAPH_SetBorder(hItem, 
                          CHECKBOX_IsChecked(WM_GetDialogItem(hDlg, GUI_ID_CHECK2)) * 40, 
                          CHECKBOX_IsChecked(WM_GetDialogItem(hDlg, GUI_ID_CHECK3)) * 5, 
                          CHECKBOX_IsChecked(WM_GetDialogItem(hDlg, GUI_ID_CHECK4)) * 5, 
                          CHECKBOX_IsChecked(WM_GetDialogItem(hDlg, GUI_ID_CHECK5)) * 5);
          break;
        case GUI_ID_SLIDER0:
          //
          // Set horizontal grid spacing
          //
          hItem = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
          Value = SLIDER_GetValue(pMsg->hWinSrc) * 10;
          GRAPH_SetGridDistX(hItem, Value);
          GRAPH_SCALE_SetTickDist(_hScaleH, Value);
          break;
        case GUI_ID_SLIDER1:
          //
          // Set vertical grid spacing
          //
          hItem = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
          Value = SLIDER_GetValue(pMsg->hWinSrc) * 5;
          GRAPH_SetGridDistY(hItem, Value);
          GRAPH_SCALE_SetTickDist(_hScaleV, Value);
          break;
        case GUI_ID_RADIO0:
          //
          // Set the widget effect
          //
          hItem = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
          switch (RADIO_GetValue(pMsg->hWinSrc)) {
          case 0:
            WIDGET_SetEffect(hItem, &WIDGET_Effect_3D);
            break;
          case 1:
            WIDGET_SetEffect(hItem, &WIDGET_Effect_Simple);
            break;
          case 2:
            WIDGET_SetEffect(hItem, &WIDGET_Effect_None);
            break;
          }
          break;
        case GUI_ID_CHECK6:
          //
          // Toggle horizontal scroll bar
          //
          hItem = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
          if (CHECKBOX_IsChecked(WM_GetDialogItem(hDlg, GUI_ID_CHECK6))) {
            GRAPH_SetVSizeX(hItem, 500);
          } else {
            GRAPH_SetVSizeX(hItem, 0);
          }
          break;
        case GUI_ID_CHECK7:
          //
          // Toggle vertical scroll bar
          //
          hItem = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
          if (CHECKBOX_IsChecked(WM_GetDialogItem(hDlg, GUI_ID_CHECK7))) {
            GRAPH_SetVSizeY(hItem, 300);
          } else {
            GRAPH_SetVSizeY(hItem, 0);
          }
          break;
        case GUI_ID_CHECK8:
          //
          // Toggle alignment
          //
          WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
          for (i = 0; i < GUI_COUNTOF(_aColor); i++) {
            if (CHECKBOX_IsChecked(WM_GetDialogItem(hDlg, GUI_ID_CHECK8))) {
              GRAPH_DATA_YT_SetAlign(_ahData[i], GRAPH_ALIGN_LEFT);
              GRAPH_DATA_YT_MirrorX (_ahData[i], 1);
            } else {
              GRAPH_DATA_YT_SetAlign(_ahData[i], GRAPH_ALIGN_RIGHT);
              GRAPH_DATA_YT_MirrorX (_ahData[i], 0);
            }
          }
          break;
        }
        break;
      }
      break;
    default:
      WM_DefaultProc(pMsg);
    }
  }
  
  /*********************************************************************
  *
  *       Public code
  *
  **********************************************************************
  */
  /*********************************************************************
  *
  *       MainTask
  */
  void MainTask(void) {
    WM_HWIN hDlg;
    WM_HWIN hGraph;
  
    hGraph = 0;
    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_SetDesktopColor(GUI_BLACK);
    #if GUI_SUPPORT_MEMDEV
      WM_SetCreateFlags(WM_CF_MEMDEV);
    #endif
    hDlg = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), _cbCallback, 0, 0, 0);
    while (1) {
      #ifdef WIN32
        GUI_Delay(10);
      #endif
      if (!_Stop) {
        if (!hGraph) {
          hGraph = WM_GetDialogItem(hDlg, GUI_ID_GRAPH0);
        }
        _AddValues();
      }
      GUI_Exec();
    }
  }
  
  /*************************** End of file ****************************/
  
  