*-----------------------------------------------------------------------------
* RmcTest.prg - based on the WinTest.prg provided with xHarbour, and used to
*                test the use of Rainer Morgen's free Rmchart.dll with xHarbour
*                and isolated from FWH (to rule it out as a problem source).
*
*              - An example of how to use a basic winapi xHb app for program
*                testing, separated from any GUI that might be a problem.
*
*              - mnSingleBars() is where most of the testing is done here.
*
*              - Must link in Rmc4xhb.prg (contains all RMChart function calls)
*-----------------------------------------------------------------------------

STATIC hRmcDll,nCtrlID,hWnd,hDC
STATIC s_oControl := NIL
STATIC lDirect := .f.

#include "hbdll.ch"

#include "winapi.ch"
#include "wingdi.ch"
#include "structures.ch"

#include "DLLxHb.ch"
#include "Rmchart.ch"

#define True   1
#define False  0


// Setup menu commands...
#define IDM_SINGLEBARS         5001
#define IDM_DIRECT             5002
#define IDM_DELETE             5003
#define IDM_FOURTH             5004
#define IDM_FIFTH              5005
#DEFINE IDM_EXIT               5006

#define IDM_SIXTH              6006
#define IDM_SEVENTH            6007
#define IDM_EIGHTH             6008
#DEFINE IDM_NINTH              6009

pragma pack(4)

typedef struct {;
  CTYPE_DOUBLE nDouble[5];
} DataStruct

typedef struct {;
  CTYPE_LONG nLong[3];
} PointsStruct

// The following line is an alternate way to define whether we're accessing 
// DLLCALL directly or indirectly via DLLxHb.ch. To use DLLCALL directly, 
// without using lDirect, uncomment this line...
//                     (now replaced by lDirect, a f-w static )
//#define __DIRECT__

#xtranslate TextOut( <x,...> ) =>

PROCEDURE Main()

*   LOCAL hWnd
   LOCAL wc := (struct WNDCLASS)
   LOCAL msg
   LOCAL hMenu, hFileMenu, hEditMenu

   wc:style         := CS_OWNDC | CS_DBLCLKS
   wc:lpfnWndProc   := WinCallBackPointer( @MainWndProc() )
   //wc:cbClsExtra    := 0
   //wc:cbWndExtra    := 0
   wc:hInstance     := GetModuleHandle()
   //wc:hIcon         := 0
   wc:hCursor       := LoadCursor( NIL, IDC_IBEAM )
   wc:hbrBackground := COLOR_WINDOW + 1
   wc:lpszClassName := "TestWindow"
   //wc:lpszMenuName  := NIL

   hRmcDll  := LoadLibrary( "RMCHART.DLL" )

   SETHandle(hRmcDll)

   IF RegisterClass( wc ) > 0

      // Make the main app window...
      hWnd := CreateWindowEx( 0, "TestWindow", ;
                              "Rmchart Tests - With Basic Winapi Window", ;
                              WS_OVERLAPPEDWINDOW, ;
                              100, 100, 800, 600, 0, 0, wc:hInstance, NIL )

      // Build the "File" menu (first menu) for the main window...
      hFileMenu := CreatePopupMenu()
      AppendMenu( hFileMenu, MF_STRING, IDM_SINGLEBARS,         "&Single Bars Graph" )
      AppendMenu( hFileMenu, MF_STRING, IDM_DIRECT,             "&Toggle Direct/Indirect DLLCALL" )
      AppendMenu( hFileMenu, MF_STRING, IDM_DELETE,             "&Delete chart" )
      AppendMenu( hFileMenu, MF_STRING, IDM_FOURTH,             "&Fourth test" )
      AppendMenu( hFileMenu, MF_STRING, IDM_FIFTH,              "F&ifth test" )
      AppendMenu( hFileMenu, MF_STRING, IDM_EXIT,               "&Exit" )

      // Build the "Edit" menu (second menu) for the main window...
      hEditMenu := CreatePopupMenu()
      AppendMenu( hEditMenu, MF_STRING, IDM_SIXTH,              "&Sixth test" )
      AppendMenu( hEditMenu, MF_STRING, IDM_SEVENTH,            "S&eventh test" )
      AppendMenu( hEditMenu, MF_STRING, IDM_EIGHTH,             "&Eighth test" )
      AppendMenu( hEditMenu, MF_STRING, IDM_NINTH,              "&Ninth test" )

      hMenu := CreateMenu()
      AppendMenu( hMenu, MF_POPUP, hFileMenu, "&RMChart tests" )
      AppendMenu( hMenu, MF_POPUP, hEditMenu, "&A second menu" )

      SetMenu( hWnd, hMenu )


      IF hWnd > 0
         ShowWindow( hWnd, SW_SHOW )

         WHILE GetMessage( @msg, 0, 0, 0 )
            TranslateMessage( msg )
            DispatchMessage( msg )
         END
      ELSE
         TraceLog( GetLastError(), FormatMessage() )
         Alert( "Failed to create window!" )
      ENDIF
   ELSE
      TraceLog( GetLastError(), FormatMessage() )
      Alert( "Failed to register class!" )
   ENDIF

   FreeLibrary( hRmcDll )

   RETURN

FUNCTION MainWndProc( hWnd, message, wParam, lParam )

   LOCAL ps
   STATIC nCnt := 0

   //TraceLog( hWnd, message, wParam, lParam )

   SWITCH message

      CASE WM_SIZE
         IF s_oControl != NIL
            s_oControl:__OnSize()
         ENDIF

         RETURN 0

      CASE WM_COMMAND        // Process menu selection...
         s_oControl := NIL

         SWITCH LOWORD( wParam )
            CASE IDM_SINGLEBARS
               IF nCnt = 0         // Prevent recursion.
                  mnSingleBars()
               ENDIF
               nCnt++
               EXIT

            CASE IDM_DIRECT
               IF !lDirect
                  lDirect := .t.
                  MessageBox(hWnd,"lDirect is true.","Info:")
               ELSE
                  lDirect := .f.
                  MessageBox(hWnd,"lDirect is false.","Info:")
               ENDIF
               EXIT

            CASE IDM_DELETE
               RMC_DELETECHART( nCtrlId )
               nCnt := 0
               EXIT

            CASE IDM_FOURTH
               TRY
                  MessageBox(hWnd,"Fourth test called - inactive.","Info:")
               CATCH
                  Alert( "Sorry, fourth option not available." )
               END
               EXIT

            CASE IDM_FIFTH
               TRY
                  MessageBox(hWnd,"Fifth test called - inactive.","Info:")
               CATCH
                  Alert( "Sorry, fifth option not available." )
               END
               EXIT

            CASE IDM_EXIT
               MessageBox(hWnd,"Please click on X at upper right corner..","Info:")
               EXIT

            CASE IDM_SIXTH
               TRY
                  MessageBox(hWnd,"Sixth test called - inactive.","Info:")
               CATCH
                  Alert( "Sorry, sixth option not available." )
               END
               EXIT

            CASE IDM_SEVENTH
               TRY
                  MessageBox(hWnd,"Seventh test called - inactive.","Info:")
               CATCH
                  Alert( "Sorry, seventh option not available." )
               END
               EXIT

            CASE IDM_EIGHTH
               TRY
                  MessageBox(hWnd,"Eighth test called - inactive.","Info:")
               CATCH
                  Alert( "Sorry, eighth option not available." )
               END
               EXIT

            CASE IDM_NINTH
               TRY
                  MessageBox(hWnd,"Ninth test called - inactive.","Info:")
               CATCH
                  Alert( "Sorry, ninth option not available." )
               END
               EXIT

         END
         RETURN 0


      CASE WM_SETFOCUS
         RETURN 0

      CASE WM_CREATE
         RETURN 0
/*
      CASE WM_PAINT
         hDC := BeginPaint( hWnd, @ps )
         //TextOut( hDC, 20, 20, "Hello World", Len( "Hello World" ) )
         EndPaint( hWnd, ps )
         IF nCnt = 0         // Prevent recursion.
            mnSingleBars()
         ENDIF
         nCnt++

         RETURN 0
*/

      CASE WM_DESTROY
         PostQuitMessage( 0 )
         TraceLog( "Quit" )
         RETURN 0
   END

RETURN DefWindowProc( hWnd, message, wParam, lParam )
*----------------------------------------------------
  // This test function for creating a bar graph necessarily uses a
  // building block approach, calling a series of Rmchart functions in sequence
  // because that is the way Rmchart creates a graph, one step at a time...
FUNCTION mnSingleBars()
    LOCAL oXpoints IS PointsStruct,;
          oYpoints IS PointsStruct,;
          cRmcFile := ""   ,;
          nAverage := 0    ,;
          nB := 0          ,;
          nL :=0           ,;
          nR := 0          ,;
          nT :=0           ,;
          nExportOnly := 0 ,;
          nRetVal := 0     ,;
          nX := 0          ,;
          nY := 0          ,;
          sRMCfile := ""   ,;    // Using "s" notation instead of "c" only to
          sTemp   := ""    ,;    //   remain consistent with orig VB6 code.
          oData IS DataStruct   // C structure built at top of this prg.

    sRMCfile := "SimpleBar.rmc"

    nCtrlID  := hWnd  // Better to use some predefined CONSTANT ID.


// IF lDirect = .t. (or __DIRECT__ in prior version) then we are invoking 
// DLLCALL() directly, without going to it through DLLxHb.ch .  The advantage
// of the indiredct approach is that the syntax is simpler, and all trailing
// params don't have to be provided because thy will automatically be provided
// as nil by DLLxHb's function calls through DLLxHb.ch .

// The reason for testing direct versus indirect calls to DLLCALL is that
// some early errors were hard to pin down, and so we needed to determine if
// the problem was in whether a function was called directely or indirectly. We
// found that this wasn't really a factor, except that when calling directly
// we had to be sure to put in commas for unused trailing params or we'd get
// a GPF.

//#ifdef __DIRECT__
IF lDirect
   nRetVal = DLLCALL( hRmcDll, DC_CALL_STD, ;
             "RMC_CREATECHART", hWnd, nCtrlID, 0, 0, ;
                       600, 450, ColorAzure, RMC_CTRLSTYLEFLAT, , , , , )

//  MessageBox(hWnd,"__DIRECT__ is T","__DIRECT__ status:")
    MessageBox(hWnd,"lDirect is T","lDIRECT status:")
//#else
ELSE
   nRetVal = RMC_CREATECHART( hWnd, nCtrlID, 0, 0, ;
                       600, 450, ColorAzure, RMC_CTRLSTYLEFLAT ) //, False, "")

//  MessageBox(hWnd,"__DIRECT__ is F","__DIRECT__ status:")
    MessageBox(hWnd,"lDirect is .f.","lDirect status:")

//#endif
ENDIF

   TraceLog( nRetVal )

    // Add Region 1... (a chart can have up to 6 spatial regions, each
    //                  displaying a different graph)
   nRetVal = RMC_ADDREGION( nCtrlID, 5, 5, -5, -5, "", False)

   TraceLog( nRetVal )

    // Add caption to region 1...
   nRetVal = RMC_ADDCAPTION( nCtrlID, 1, "This is our chart's caption", ;
                          ColorBlue, ColorYellow, 11, True)
   TraceLog( nRetVal )

    // Add grid to region 1...
   nRetVal = RMC_ADDGRID( nCtrlID, 1, ColorBeige, False, 0, 0, 0, 0, ;
               RMC_BICOLOR_LABELAXIS)

   TraceLog( nRetVal )

    // Add data axis to region 1...
   nRetVal = RMC_ADDDATAAXIS( nCtrlID, 1, 1, 0.0, 100.0, 11, 8, ;
               ColorBlack, ColorBlack, RMC_LINESTYLEDOT, 0, "$", "Axis Text", ;
               , RMC_TEXTCENTER )

   TraceLog( nRetVal )

    // One rudimentary way of displaying debugging progress points onscreen...
** TextOut( hDC, 60, 20, "did RMC_ADDDATAAXIS.", Len( "did RMC_ADDDATAAXIS." ) )

   // Add label axis to region 1...   (no problem here)
   sTemp = "Label A*Label B*Label C*Label D*Label E"

   nRetVal =  ;
     RMC_ADDLABELAXIS( nCtrlID, 1, sTemp, 1, 5, RMC_LABELAXISBOTTOM, 8, ;
                 ColorBlack, RMC_TEXTCENTER, ColorBlack, RMC_LINESTYLENONE, "")


    // Add Series 1 to region 1...
    // Read data values...

    // First, load data into C structure array object...
    // (in your app, can load this data from database or wherever)
    oData:nDouble[1] := 60.0    // Your data goes into these 5 slots
    oData:nDouble[2] := 70.0
    oData:nDouble[3] := 40.0
    oData:nDouble[4] := 60.0
    oData:nDouble[5] := 30.0

   // All Rmchart data arrays have to be passed as a C array in a structure,
   // a kind of object, and are passed like oData... 

   nRetVal = RMC_ADDBARSERIES( nCtrlID, 1, oData, 5, RMC_BARSINGLE, ;
            RMC_BAR_FLAT_GRADIENT2, False, ColorCornflowerBlue, False, 1, ;
            RMC_VLABEL_NONE, 1, RMC_HATCHBRUSH_OFF )

    // Set third bar's color to Red...    
   RMC_SETSERIESCOLOR( nCtrlID, 1, 1, ColorRed, 3 )


    nAverage := 0.0
    nL := 0; nT := 0; nR := 0; nB := 0

    // Calc the average...
   nRetVal := RMC_CalcAverage( nCtrlID, 1, 1, @nAverage, @nL, @nT, @nR, @nB )

   TraceLog( nRetVal, nAverage,  nL, nT, nR, nB )

    // Draw the average line...       

  RMC_CODASH( nCtrlID, 1, nL, nT, nR, nB, RMC_LINE_FLAT, ColorGreen, False, 2 )

    // Add a legend for the average line:
    oXPoints:nLong[1] = 480; oXPoints:nLong[2] = 565; oXPoints:nLong[3] = 565
    oYPoints:nLong[1] = 185; oYPoints:nLong[2] = 185; oYPoints:nLong[3] = 218

   nRetVal := RMC_COLine( nCtrlID, 2, oXPoints, oYPoints, 3, RMC_LINE_FLAT, ;
                ColorGreen, 0, 2, 0, RMC_ANCHOR_ARROW_OPEN )
   TraceLog( nRetVal )

   nRetVal := RMC_COText( nCtrlID, 3, "Average: " + TRANSFORM(nAverage, "99.99"), 480, 169 )

   TraceLog( nRetVal )

   nRetVal = RMC_PAINT( nCtrlID )

   TraceLog( nRetVal )

   // Show the chart...
   nRetVal = RMC_DRAW( nCtrlID )

   TraceLog( nRetVal )

RETURN nil
*---------------------------------
// dummy funcs to mask some FWH funcs...
FUNCTION OEMTOCHARA() ; RETURN nil
FUNCTION SysRefresh() ; RETURN nil
FUNCTION CursorWait() ; RETURN nil
FUNCTION CursorArrow() ; RETURN nil
*----------------------------------------------------
*--------------------------------------------------------
