Converting Clipper Applications

CONVERTING @..SAYS...Converting @SAYS from text to GUI
CONVERTING ACHOICE().Converting ACHOICE() from text to GUI
CONVERTING DBEDIT()..Converting DBEDIT() from text to GUI
CONVERTING GETS......Converting @SAY..GETS from text to GUI
CONVERTING MEMOEDIT()Converting MEMOEDIT() from text to GUI
CONVERTING MENUS.....Converting @PROMPT menus from text to GUI
CONVERTING PRINT.....Converting Printer @..SAYS

CONVERTING @..SAYS

Converting @SAYS from text to GUI

Description:

    Working with @..SAYS is not as straight forward as working
    with AChoice() or Dbedit() because @..SAYS usually used in
    Clipper applications for a variety of screen functions.  For
    example, it is not possible to create a GUI conversion
    system that can convert any text-based screen to a GUI-based
    dialogue because the conversion program simply cannot
    decipher the "intent" of the programmer by looking at either
    the code or the screen.
   
    It is possible, however, to break down some @SAY scenarios
    into pieces that can be managed with Dual-Mode functions.
   
    Let's look at the following Clipper @SAY scenario:
   
    We want to display a series of messages on the screen as
    we are progressing through the updating of a database
    structure.  The original Clipper source code might look
    something like this:
   
     cScreen := SaveScreen( 3,5,16,50 )
     @ 3,5 TO 16,50
     @ 4,6 CLEAR TO 15,49
     @ 6,10 SAY 'Creating Backup..'
     Backup()
     @ 8,10 SAY 'Copying Structure ..'
     CopyStru()
     @ 10,10 SAY 'Modifying Structure..'
     ModiStru()
     @ 12,10 SAY 'Appending from Backup..'
     AppendBack()
     @ 14,10 SAY 'Done!  Press any key to continue'
     Inkey(0)
     RestScreen( 3,5,14,75,cScreen)
   
   
    The above code can be easily modified to Dual-Mode because
    the @..SAYS are organized in a "window" area of the screen
    and because they are simply status messages which are
    displayed during the progress of the program.  To accomplish
    this task we use the Dual-Mode functions: DC_EXPL(), DC_IMPL()
    DC_SAY(), and DC_CLS() or the Dual-Mode commands: DCEXPLODE,
    DCIMPLODE, @..SAYWIN, and CLS (contained in EXPRESS.CH).
   
    The command DCEXPLODE paints a box on the screen and returns an
    array of information about this new "object" which includes saved
    screen contents (in TEXT mode) or a reference to a Dialog object
    (in GUI mode).  @..SAYWIN is translated in EXPRESS.CH to paint the
    says on the parent object.  If no parent object is included in
    the @..SAYWIN command, then the last object created by DCEXPLODE
    is assumed to be the parent, otherwise the full screen is used as
    the parent.  If the GUI flag is on, then the screen object will
    be a GUI dialog box.   The command DCIMPLODE is used to restore
    the screen area (in Text mode) or destroy the parent dialogue
    object (in GUI mode).
   
     /* ----------------------- */
   
     #include "express.ch"
   
     FUNCTION XTest()
   
     LOCAL aScreen
   
     GUI ON  // turn on GUI mode
   
     @ 3, 5, 16, 50 DCEXPLODE aScreen FONT "10.courier"
   
     @ 2,5 SAYWIN 'Creating Backup..'
     DC_Pause(1)
     Backup()
   
     @ 4,5 SAYWIN 'Copying Structure ..'
     DC_Pause(1)
     CopyStru()
   
     @ 6,5 SAYWIN 'Modifying Structure..'
     DC_Pause(1)
     ModiStru()
   
     @ 8,5 SAYWIN 'Appending from Backup..'
     DC_Pause(1)
     AppendBack()
   
     DCIMPLODE aScreen
   
     RETURN nil
   
     /* ----------------------- */
   
     NOTE: These examples are here for general guidelines on how
     to approach the conversion of existing code to GUI, not
     because it is a recommended method of application conversion.
     After studying the examples in \express\sample by running
     XDEMO.EXE, it will become more clear on how to approach the
     conversion of your application to GUI.  EXPRESS.CH is a very
     simplistic approach to understanding how the preprocessor can
     be used in a variety of ways to create a command interface to
     Xbase++ parts which resembles or closely emulates Clipper text-
     based syntax.  The recommended approach to converting Clipper
     applications is to study DCDIALOG.CH and the DC* commands.
     This is a much more robust command set specifically designed to
     produce a full GUI application that is easy to write and
     maintain.
   

Source/Library:

  EXPRESS.CH, DCDIALOG.CH

See Also:

   dc_expl()
   dc_say()



CONVERTING ACHOICE()

Converting ACHOICE() from text to GUI

Description:

    Let's look at the following Clipper ACHOICE() scenario:
   
    We have a field list which we want to browse on the screen
    by first saving a screen area,  painting a box on the screen,
    creating an ACHOICE() pick-list in the the boxed area,
    choosing a field, then restoring the original screen.  The
    original code might look something like this:
   
     FUNCTION Xtest()
   
     LOCAL cScreen, aFields, nField
   
     cScreen := SaveScreen( 3,5,20,25 )
     @ 3,5 TO 20,25
     @ 4,6 CLEAR TO 19,24
     USE COLLECT
     aFields := Array(Fcount())
     AFields(aFields)
     nField := AChoice( 4, 6, 19, 24, aFields )
     RestScreen( 3,5,14,25,cScreen)
   
     RETURN nField
   
     /* --------------------- */
   
     Now we want to change the code to display the same Browse in
     a Windows GUI dialogue box:
   
     FUNCTION Xtest()
   
     #include "express.ch"
   
     LOCAL aFields, nField
   
     * cScreen := SaveScreen( 3,5,20,25 ) // this isn't needed
     * @ 3,5 TO 20,25                     // this isn't needed
     * @ 4,6 CLEAR TO 13,74               // this isn't needed
     GUI ON   // turn on GUI mode
     USE COLLECT
     aFields := Array(Fcount())
     AFields(aFields)
     nField := AChoice( 4, 6, 19, 24, aFields )
     * RestScreen( 3,5,14,25,cScreen)     // this isn't needed
   
     RETURN nField
   
     /* -------------- */
   
     That's all there is to it.  "express.ch" translates the
     ACHOICE() function to call DC_ACHOICE() which is a Dual-Mode
     function.
   

Source/Library:

  EXPRESS.CH

See Also:

   dc_achoice()



CONVERTING DBEDIT()

Converting DBEDIT() from text to GUI

Description:

    Let's look at the following Clipper DBEDIT() scenario:
   
    We have a database which we want to browse on the screen by
    first saving a screen area,  painting a box on the screen,
    creating an DBEDIT() browse in the the boxed area, choosing
    a field, then restoring the original screen.  The original
    code might look something like this:
   
   
     FUNCTION Xtest1()
   
     LOCAL cScreen
   
     cScreen := SaveScreen( 3,5,20,75 )
     @ 3,5 TO 20,75
     @ 4,6 CLEAR TO 19,74
     USE COLLECT VIA DBFNTX
     DbEdit( 4, 6, 19, 74 )
     RestScreen( 3,5,14,75,cScreen)
   
     RETURN nil
   
     /* ---------------------- */
   
     Now we want to change the code to display the same Browse in
     a Windows GUI dialogue box:
   
     FUNCTION XTest2()
   
     #include "express.ch"
   
     * cScreen := SaveScreen( 3,5,20,75 ) // this isn't needed
     * @ 3,5 TO 20,75                     // this isn't needed
     * @ 4,6 CLEAR TO 13,74               // this isn't needed
     GUI ON  // turn on GUI mode
     USE COLLECT VIA DBFNTX
     DbEdit( 4, 6, 19, 74 )
     * RestScreen( 3,5,14,75,cScreen)     // this isn't needed
   
     RETURN nil
   
     /* ------------------ */
   
     That's all there is to it.  "express.ch" translates the
     DBEDIT() function to call DC_DBEDIT() which is a Dual-Mode
     function.
   

Source/Library:

  EXPRESS.CH

See Also:

   dc_dbedit()



CONVERTING GETS

Converting @SAY..GETS from text to GUI

Description:

    Let's look at the following Clipper @SAY..GET scenario:
   
    We have a table of GETS which we want to display on the screen
    by first saving a screen area,  painting a box on the screen,
    writing all the GETS in the boxed area, editing the gets,
    then restoring the original screen.  The code might look
    something like this:
   
   
     FUNCTION Xtest1()
   
     LOCAL GetList, cLastName := Space(15), cFirstName := Space(15), ;
           cCompany := Space(30), cStreet := Space(30), cCity := Space(25), ;
           cState := Space(10), cCountry := Space(20), cPhone := Space(12), ;
           cScreen
   
     cScreen := SaveScreen( 3,5,14,75 )
     @ 4,6 CLEAR TO 13,74
     GetList := {}
     @ 5,10 SAY ' Last Name' GET cLastName VALID !Empty(cLastName)
     @ 5,40 SAY 'First Name' GET cFirstName VALID !Empty(cFirstName)
     @ 7,10 SAY '   Company' GET cCompany
     @ 8,10 SAY '    Street' GET cStreet VALID !Empty(cStreet)
     @ 9,10 SAY '      City' GET cCity VALID !Empty(cCity)
     @10,10 SAY '     State' GET cState PICT '@!' ;
                             VALID StateValid(cState)
     @10,40 SAY '   Country' GET cCountry PICT '@!' ;
                             VALID CountryValid(cCountry)
     @12,40 SAY '     Phone' GET cPhone PICT '(999)-999-9999'
     READ
     RestScreen( 3,5,14,75,cScreen)
   
     RETURN nil
   
     /* ------------------------- */
   
     STATIC FUNCTION StateValid(cState)
   
     IF !( ' ' + Alltrim(cState) $ ' AL AK AZ CA MI MN NY NSW ' )
        DC_MsgBox('State must be AK, AK, AZ, CA, MI, MN, NY or NSW')
        RETURN .f.
     ENDIF
     RETURN .t.
   
     /* ------------------------- */
   
     STATIC FUNCTION CountryValid(cCountry)
   
     IF !( ' ' + Alltrim(cCountry) $ ' USA CANADA GERMANY ' )
        DC_MsgBox('Country must be USA, CANADA or GERMANY')
        RETURN .f.
     ENDIF
     RETURN .t.
   
     /* -------------------------- */
   
     Now we want to change the code to display the same GETS in a
     Windows GUI dialogue box:
   
     FUNCTION Xtest2()
   
     #include "express.ch"
   
     LOCAL GetList, cLastName := Space(15), cFirstName := Space(15), ;
           cCompany := Space(30), cStreet := Space(30), cCity := Space(25), ;
           cState := Space(10), cCountry := Space(20), cPhone := Space(12)
   
     * cScreen := SaveScreen( 3,5,14,75 ) // this isn't needed
     * @ 4,6 CLEAR TO 13,74               // this isn't needed
     GUI ON  // turn on GUI mode
     GetList := {}
     @ 5,10 SAY ' Last Name' GET cLastName VALID !Empty(cLastName)
     @ 5,40 SAY 'First Name' GET cFirstName VALID !Empty(cFirstName)
     @ 7,10 SAY '   Company' GET cCompany
     @ 8,10 SAY '    Street' GET cStreet VALID !Empty(cStreet)
     @ 9,10 SAY '      City' GET cCity VALID !Empty(cCity)
     @10,10 SAY '     State' GET cState PICT '@!' ;
                             VALID StateValid(cState)
     @10,40 SAY '   Country' GET cCountry PICT '@!' ;
                             VALID CountryValid(cCountry)
     @12,40 SAY '     Phone' GET cPhone PICT '(999)-999-9999'
     READ
     * RestScreen( 3,5,14,75,cScreen)     // this isn't needed
   
     RETURN nil
   
     That's all there is to it.  "express.ch" translates the
     @SAY..GETS so that they add a new kind of object to the Getlist
     array and it translates the READ command so it passes the
     Getlist array to DC_ReadGui() instead of ReadModal().
   
     NOTE: These examples are here for general guidelines on how
     to approach the conversion of existing code to GUI, not
     because it is a recommended method of application conversion.
     After studying the examples in \express\sample by running
     XDEMO.EXE, it will become more clear on how to approach the
     conversion of your application to GUI.  EXPRESS.CH is a very
     simplistic approach to understanding how the preprocessor can
     be used in a variety of ways to create a command interface to
     Xbase++ parts which resembles or closely emulates Clipper text-
     based syntax.  The recommended approach to converting Clipper
     applications is to study DCDIALOG.CH and the DC* commands.
     This is a much more robust command set specifically designed to
     produce a full GUI application that is easy to write and
     maintain.
   

Source/Library:

  DCDIALOG.CH, EXPRESS.CH

See Also:

   DCREAD GUI
   dc_readgui()



CONVERTING MEMOEDIT()

Converting MEMOEDIT() from text to GUI

Description:

    Let's look at the following Clipper MemoEdit() scenario:
   
    We have a memo which we want to edit on the screen
    by first saving a screen area,  painting a box on the screen,
    running the Memo Editor, then restoring the original screen.
    The code might look something like this:
   
     FUNCTION Xtest1()
   
     LOCAL cScreen, cMemo
   
     cScreen := SaveScreen( 5,5,20,75 )
     @ 5,5 CLEAR TO 20,75
     @ 5,5 TO 20,75 DOUBLE
   
     cMemo := MemoRead('README.TXT')
   
     cMemo := MemoEdit(cMemo,6,6,19,74)
   
     MemoWrit( 'README.TXT', cMemo )
   
     RestScreen( 8,5,20,75,cScreen)
   
     RETURN cMemo
   
     /* ----------------------- */
   
     Now we want to change the code to display the memo editor
     in a Windows GUI dialogue box:
   
   
     FUNCTION Xtest2()
   
     #include "express.ch"
   
     LOCAL cScreen, cMemo
   
     GUI ON // turn on GUI mode
     * cScreen := SaveScreen( 5,5,20,75 )    this is not needed
     * @ 5,5 CLEAR TO 20,75                  this is not needed
     * @ 5,5 TO 20,75 DOUBLE                 this is not needed
   
     cMemo := MemoRead('README.TXT')
   
     cMemo := MemoEdit(cMemo,6,6,19,74)
   
     MemoWrit( 'README.TXT', cMemo )
   
     * RestScreen( 8,5,20,75,cScreen)        this is not needed
   
     RETURN cMemo
   
     /* ------------------ */
   
     That's all there is to it.  "express.ch" translates the
     MEMOEDIT() function to call DC_MEMOEDIT() which is a Dual-Mode
     function.
   

Source/Library:

  EXPRESS.CH

See Also:

   dc_memoedit()



CONVERTING MENUS

Converting @PROMPT menus from text to GUI

Description:

    Let's look at the following Clipper Menu scenario:
   
    We have a menu which we want to display on the screen
    by first saving a screen area,  painting a box on the screen,
    writing all the menu PROMPTS in the boxed area, running the
    menu, then restoring the original screen.  The code might look
    something like this:
   
     FUNCTION Xtest1()
   
     LOCAL cScreen, PromptList, nChoice
   
     cScreen := SaveScreen( 8,5,16,75 )
     @ 8,5 CLEAR TO 16,75
     @ 8,5 TO 15,75 DOUBLE
     PromptList := {}
     SET WRAP ON
     SET MESSAGE TO 16 CENTER
   
     @ 10,10 PROMPT ' Enter New Names ' ;
             MESSAGE 'Add new names and addresses'
     @ 11,10 PROMPT ' Print List      ' ;
             MESSAGE 'Print the Customer List'
     @ 12,10 PROMPT ' Dial            ' ;
             MESSAGE 'Dial customers starting at top of list'
     @ 13,10 PROMPT ' Import          ' ;
             MESSAGE 'Import a new Customer List'
   
     @ 10,40 PROMPT ' Manager         ' ;
             MESSAGE 'Run the Database Manager'
     @ 11,40 PROMPT ' Calendar        ' ;
             MESSAGE 'Check the Appointment Schedule'
     @ 12,40 PROMPT ' Purge           ' ;
             MESSAGE 'Remove all the dialed numbers from the list'
     @ 13,40 PROMPT ' Exit            ' ;
             MESSAGE 'Quit the program'
   
     MENU TO nChoice
     RestScreen( 8,5,16,75,cScreen)
   
     RETURN nChoice
   
     /* ----------------------- */
   
     Now we want to change the code to display the same PROMPTS
     in a Windows GUI dialogue box:
   
   
     FUNCTION Xtest2()
   
     LOCAL PromptList, nChoice
   
     #include "express.ch"
   
     * cScreen := SaveScreen( 3,5,15,75 )  // don't need this
     * @ 3,5 TO 15,75 DOUBLE               // don't need this
     * @ 4,6 CLEAR TO 14,74                // don't need this
     PromptList := {}
     SET WRAP ON
     SET MESSAGE TO 16 CENTER
     GUI ON // turn on GUI
   
     @ 10,10 PROMPT ' Enter New Names ' ;
             MESSAGE 'Add new names and addresses'
     @ 11,10 PROMPT ' Print List      ' ;
             MESSAGE 'Print the Customer List'
     @ 12,10 PROMPT ' Dial            ' ;
             MESSAGE 'Dial customers starting at top of list'
     @ 13,10 PROMPT ' Import          ' ;
             MESSAGE 'Import a new Customer List'
   
     @ 10,40 PROMPT ' Manager         ' ;
             MESSAGE 'Run the Database Manager'
     @ 11,40 PROMPT ' Calendar        ' ;
             MESSAGE 'Check the Appointment Schedule'
     @ 12,40 PROMPT ' Purge           ' ;
             MESSAGE 'Remove all the dialed numbers from the list'
     @ 13,40 PROMPT ' Exit            ' ;
             MESSAGE 'Quit the program'
   
     MENU TO nChoice
   
     * RestScreen( 3,5,15,75,cScreen)     // don't need this
   
     RETURN nChoice
   
     /* --------------------- */
   
     That's all there is to it.  "express.ch" translates the
     @PROMPTS so that they add a new kind of object to the
     PromptList array and it translates the MENU TO command so it
     passes the PromptList array to DC_MenuTo() instead of _MenuTo().
   
     NOTE: These examples are here for general guidelines on how
     to approach the conversion of existing code to GUI, not
     because it is a recommended method of application conversion.
     After studying the examples in \express\sample by running
     XDEMO.EXE, it will become more clear on how to approach the
     conversion of your application to GUI.  EXPRESS.CH is a very
     simplistic approach to understanding how the preprocessor can
     be used in a variety of ways to create a command interface to
     Xbase++ parts which resembles or closely emulates Clipper text-
     based syntax.  The recommended approach to converting Clipper
     applications is to study DCDIALOG.CH and the DC* commands.
     This is a much more robust command set specifically designed to
     produce a full GUI application that is easy to write and
     maintain.
   

Source/Library:

  EXPRESS.CH

See Also:

   dc_menu_to()



CONVERTING PRINT

Converting Printer @..SAYS

Description:

    Let's look at the following Clipper Print @..SAY scenario:
   
    We have a columnar report in which we want to give the user
    the option of choosing a printer, such as a network printer
    or a fax, a starting and ending page, a font, and the number
    of rows and columns on the paper.
   
    The original Clipper report looks like this:
   
   
     FUNCTION MyReport ( nCopies )
   
     LOCAL nRow, nSaveRec, cScrn, aFor_Sale, i, nPage
   
     SELE collect
     nSaveRec := RecNo()
     GO TOP
   
     aFor_Sale := { 'No','Yes','Not Sure' }
   
     SET DEVICE TO PRINT
   
     cScrn := DC_WaitOn('Printing..')
   
     FOR i := 1 TO nCopies
   
       GO TOP
       nRow := 1
       nPage := 1
       DO WHILE !Eof()
   
         IF nRow = 1
   
           @ nRow,10 SAY 'My Personal Collection Inventory'
           @ nRow,50 SAY 'Page ' + Alltrim(Str(nPage))
           @ nRow,70 SAY Date()
   
           nRow += 2
   
           @ nRow,0  SAY 'Description'
           @ nRow,35 SAY 'Type'
           @ nRow,50 SAY 'Sub-Type'
           @ nRow,65 SAY 'Cond'
           @ nRow,71 SAY 'For Sale?'
           @ nRow,82 SAY 'Value'
           nRow += 2
   
         ELSE
   
           @ nRow,0  SAY COLLECT-þ>descrip
           @ nRow,35 SAY COLLECT-þ>type
           @ nRow,50 SAY COLLECT-þ>sub_type
           @ nRow,65 SAY COLLECT-þ>condition
           @ nRow,71 SAY aFor_Sale[COLLECT-þ>for_sale+1]
           @ nRow,82 SAY Str(COLLECT-þ>appr_value,7,2)
           nRow++
   
           SKIP
   
           IF nRow þ> 60
             EJECT
             nRow := 1
           ENDIF
   
         ENDIF
   
       ENDDO
   
     NEXT
   
     SET DEVICE TO SCREEN
     DC_Impl(cScrn)
   
     GO nSaveRec
     RETURN nil
   
    -----------------------------------------------------------
   
    The modified report looks like this:
   
     #include "DCPRINT.CH"
   
     FUNCTION MyReport ( )
   
     LOCAL nRow, nSaveRec, cScrn, aFor_Sale, oPrinter, i, nPage
   
     SELE collect
     nSaveRec := RecNo()
     GO TOP
   
     aFor_Sale := { 'No','Yes','Not Sure' }
   
     BEGIN SEQUENCE
   
     DCPRINT ON TO oPrinter // Pop-Up printer dialog
   
     cScrn := DC_WaitOn('Printing..')
   
     FOR i := 1 TO oPrinter:nCopies
   
       GO TOP
       nRow := 1
       oPrinter:nPage := 1
   
       DO WHILE !Eof()
   
         IF nRow = 1
   
           @ nRow,10 DCPRINT SAY 'My Personal Collection Inventory'
           @ nRow,50 DCPRINT SAY 'Page ' + Alltrim(Str(oPrinter:nPage))
           @ nRow,70 DCPRINT SAY Date()
   
           nRow += 2
   
           @ nRow,0  DCPRINT SAY 'Description'
           @ nRow,35 DCPRINT SAY 'Type'
           @ nRow,50 DCPRINT SAY 'Sub-Type'
           @ nRow,65 DCPRINT SAY 'Cond'
           @ nRow,71 DCPRINT SAY 'For Sale?'
           @ nRow,82 DCPRINT SAY 'Value'
           nRow += 2
   
         ELSE
   
           @ nRow,0  DCPRINT SAY COLLECT-þ>descrip
           @ nRow,35 DCPRINT SAY COLLECT-þ>type
           @ nRow,50 DCPRINT SAY COLLECT-þ>sub_type
           @ nRow,65 DCPRINT SAY COLLECT-þ>condition
           @ nRow,71 DCPRINT SAY aFor_Sale[COLLECT-þ>for_sale+1]
           @ nRow,82 DCPRINT SAY Str(COLLECT-þ>appr_value,7,2)
           nRow++
   
           SKIP
   
           IF nRow þ> ( oPrinter:nRows - 5 )
             DCPRINT EJECT
             nRow := 1
           ENDIF
   
         ENDIF
   
       ENDDO
   
     NEXT
   
     END SEQUENCE
   
     DCPRINT OFF
     DC_Impl(cScrn)
   
     GO nSaveRec
     RETURN nil
   
   
     The structure of the report does not change.  Only the syntax
     of a few commands are required to change like so:
   
      From                          To
     ---------------------------  ------------------------------------
     SET DEVICE TO PRINT           DCPRINT ON [ TO <þoPrinterþ> ]
     SET PRINT ON                  DCPRINT ON [ TO <þoPrinterþ> ]
     @ <þnRowþ>,<þnColþ> SAY <þcTextþ>   @ <þnRowþ>,<þnColþ> DCPRINT SAY
   <þcTextþ>
     EJECT                         DCPRINT EJECT
     SET DEVICE TO SCREEN          DCPRINT OFF
     ?/?? <þcTextþ>                  DCPRINT ?/?? <þcTextþ>
   
     Additional commands can then be added to the report to
     improve the output like so:
   
     DCPRINT FONT <þcFontNameþ>
     @ <þnSrowþ>,<þnSColþ>,<þnERowþ>,<þnEColþ> DCPRINT BOX <þOPTIONSþ>
     @ <þnSrowþ>,<þnSColþ>,<þnERowþ>,<þnEColþ> DCPRINT BITMAP <þcBitMapþ>
   

Source/Library:

  DCPRINT.CH