home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic 4 Unleashed / Visual_Basic_4_Unleashed_SAMS_Publishing_1995.iso / repease / rep.c < prev    next >
C/C++ Source or Header  |  1995-07-18  |  103KB  |  2,612 lines

  1. /*==============================================================================
  2.    REP.C
  3.    ReportEase Plus - Window process and painting functions.
  4.  
  5.    ReportEase Plus
  6.    Version 2.0
  7.  
  8.    Sub Systems, Inc.
  9.    ReportEase Plus, Copyright (c) 1993, Sub Systems, Inc. All Rights Reserved.
  10.    159 Main Street, #8C, Stoneham,  MA 02180 
  11.    (617) 438-8901.
  12.  
  13.    Software License Agreement  (1993)              
  14.    ----------------------------------
  15.    This license agreement allows the purchaser the right to modify the 
  16.    source code to incorporate in their application.
  17.    The target application must not be distributed as a standalone report writer
  18.    or a mail merge product.
  19.    Sub Systems, Inc. reserves the right to prosecute anybody found to be 
  20.    making illegal copies of the executable software or compiling the source
  21.    code for the purpose of selling there after.
  22.  
  23. ===============================================================================*/
  24.  
  25. #include "windows.h"
  26.  
  27. #if defined (_WIN32)
  28.    #if !defined(WIN32)
  29.      #define WIN32
  30.    #endif
  31. #endif
  32. #if !defined(WIN32) 
  33.   #include "print.h"
  34. #endif
  35.  
  36. #include "stdio.h"
  37. #include "stdlib.h"
  38. #include "ctype.h"
  39. #include "dos.h"
  40. #include "fcntl.h"
  41. #include "io.h"
  42. #include "signal.h"
  43. #include "string.h"
  44. #include "malloc.h"
  45. #include "memory.h"
  46. #include "sys\types.h"
  47. #include "sys\stat.h"
  48. #include "setjmp.h"
  49.  
  50. #include "rep.h"
  51.  
  52. #define  PREFIX 
  53. #include "rep1.h"
  54.  
  55. /****************************************************************************
  56.    form:
  57.    This routine simply call FORM initialization routine.  The routine
  58.    returns a 0 if successful, otherwise it returns an error code. see
  59.    ERR_ in rew.h file.
  60. *****************************************************************************/
  61. int WINAPI _export form(struct StrForm far *ArgPtr)
  62. {
  63.    int result,WinVer;
  64.    
  65.    // prepare to return an error code
  66.    #if defined (WIN32)
  67.       if (setjmp(FrAbort)==-1) return ErrorCode; // Fatal error return location 
  68.    #else
  69.       if (Catch((LPCATCHBUF)&FrAbort)==-1) return ErrorCode; // Fatal error return location 
  70.    #endif
  71.  
  72.    SessionType='F';                    // form editor session 
  73.    FormArg=(*ArgPtr);
  74.  
  75.    //* Transfer the some input parameter variables to the global area *
  76.    strcpy(FrFileName,FormArg.file);    // current report file name 
  77.    FrShowHorBar=FormArg.ShowHorBar;    // show horizontal scroll bar 
  78.    FrShowVerBar=FormArg.ShowVerBar;    // show vertical scroll bar 
  79.  
  80.    //hFrInst=FormArg.hInst;           //  uncomment for STATIC linking
  81.    //hFrPrevInst=FormArg.hPrevInst;   //  uncomment for STATIC linking
  82.  
  83.    hFrParentWnd=FormArg.hParentWnd;    // Handle to the parent window 
  84.  
  85.    //************ initialize other variables **********
  86.    UseScreen=TRUE;
  87.    FormArg.modified =FALSE;
  88.  
  89.    //********************** assign the default font and point size *********
  90.    if (FormArg.FontTypeFace[0]==0) {
  91.       WinVer=(int)GetVersion();
  92.       if ((LOBYTE(WinVer))==3 && (HIBYTE(WinVer))==0) {    // windows 3.0 
  93.           lstrcpy(FormArg.FontTypeFace,"Helv");
  94.       }
  95.       else {                                               // windows 3.1 
  96.           lstrcpy(FormArg.FontTypeFace,"Arial");
  97.       }
  98.    }
  99.  
  100.    if (0!=(result=InitFr(FormArg.style,FormArg.x,FormArg.y,FormArg.width,FormArg.height))) return result;
  101.    
  102.    FormArg.open=TRUE;  // mark this window as open 
  103.    
  104.    (*ArgPtr)=FormArg;   // pass back the updated structure
  105.  
  106.    return 0;
  107.  
  108. /****************************************************************************
  109.    RepSetMsgCallback:
  110.    This function is called by the application to set a call back function to
  111.    receive the DLL messages.  This function is needed only by the application
  112.    which do not have the capability to receive Windows messages.
  113. *****************************************************************************/
  114. int WINAPI _export RepSetMsgCallback(MSG_CALLBACK funct)
  115. {
  116.    MsgCallback=funct;
  117.    return TRUE;
  118. }
  119.  
  120. /******************************************************************************
  121.    LibMain: Function to initialize DLL
  122. ******************************************************************************/
  123. #if defined (WIN32)
  124.    BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD reason, LPVOID reserved)
  125. #else
  126.    int CALLBACK LibMain(HINSTANCE hInstance, WORD wDataSeg, WORD cbHeapSize,  LPSTR lpszCmdLine)
  127. #endif
  128. {
  129.     // process the 'reason' flag for WIN32
  130.     #if defined (WIN32)
  131.        Win32=TRUE;
  132.        if (reason == DLL_PROCESS_DETACH) return WEP(0);
  133.        if (reason != DLL_PROCESS_ATTACH) return TRUE;
  134.     #else
  135.        Win32=FALSE;
  136.     #endif
  137.  
  138.     hFrInst=hInstance;
  139.     hFrPrevInst=0;
  140.  
  141.     return TRUE;
  142. }
  143.  
  144. /*****************************************************************************
  145.     WEP:
  146.     Library exit routine.
  147. ******************************************************************************/
  148. int CALLBACK _export WEP(int nParameter)
  149. {
  150.     return 1;
  151. }
  152.  
  153. /****************************************************************************
  154.     FrWndProc:
  155.     This routine process the messages coming to the main FORM window.
  156. ****************************************************************************/
  157.  
  158. LRESULT CALLBACK _export FrWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
  159. {
  160.     int opt,i;
  161.  
  162.  
  163.     if (WindowBeingCreated) return (DefWindowProc(hWnd, message, wParam, lParam));
  164.  
  165.     //*********** translate accelerator ***********
  166.     if (FrTranslateAccelerator(hWnd,message,wParam,lParam)) return TRUE; // accelerator translated 
  167.  
  168.     switch (message) {
  169.         case WM_INITMENU:                     // initialize menu 
  170.             if ((GetMenu(hWnd)!=(HMENU)wParam)) break;
  171.             FrInitMenu((HMENU)wParam);break;
  172.  
  173.         case WM_VSCROLL:                      // vertical scroll bar commands 
  174.             switch (SCROLL_MSG(wParam,lParam)) {
  175.                 case SB_LINEDOWN:             // scroll window one line down 
  176.                    FrWinDown();break;
  177.                 case SB_LINEUP:               // scroll window one line up 
  178.                    FrWinUp();break;
  179.                 case SB_PAGEDOWN:             // next page 
  180.                    FrWinOrgY+=FrWinHeight/2;
  181.                    PaintFlag=PAINT_WIN;FrPaint();break;
  182.                 case SB_PAGEUP:               // previous page 
  183.                    FrWinOrgY-=FrWinHeight/2;
  184.                    PaintFlag=PAINT_WIN;FrPaint();break;
  185.                 case SB_THUMBTRACK:           // absolute line position as the thump moves
  186.                    FrWinOrgY=(int)(((long)FrHeight*THUMB_POS(wParam,lParam))/(VER_SCROLL_MAX-VER_SCROLL_MIN));
  187.                    PaintFlag=PAINT_WIN;FrPaint();break;
  188.                 default:
  189.                    break;
  190.             }
  191.             break;
  192.         case WM_HSCROLL:                      // horizontal scroll bar commands 
  193.             switch (SCROLL_MSG(wParam,lParam)) {
  194.                 case SB_LINEDOWN:             // scroll window one column toward right 
  195.                    FrWinRight();break;
  196.                 case SB_LINEUP:               // scroll window one column toward left 
  197.                    FrWinLeft();break;
  198.                 case SB_PAGEDOWN:             // next horizontal page 
  199.                    FrWinOrgX+=FrWinWidth/2;
  200.                    PaintFlag=PAINT_WIN;FrPaint();break;
  201.                 case SB_PAGEUP:               // previous horizontal page 
  202.                    FrWinOrgX-=FrWinWidth/2;
  203.                    PaintFlag=PAINT_WIN;FrPaint();break;
  204.                 case SB_THUMBTRACK:           // absolute column position as the thump moves
  205.                    FrWinOrgX=(int)(((long)FrWidth*THUMB_POS(wParam,lParam))/(HOR_SCROLL_MAX-HOR_SCROLL_MIN));
  206.                    PaintFlag=PAINT_WIN;FrPaint();break;
  207.                 default:
  208.                    break;
  209.             }
  210.             break;
  211.         case WM_COMMAND:
  212.             if (FrHelpWanted) {              // show contect sensitive help if requrested 
  213.                 WinHelp(hWnd,FrHelpFile,HELP_CONTEXT,wParam);
  214.                 FrHelpWanted=FALSE;
  215.                 break;
  216.             }
  217.             if (UndoItem && wParam!=ID_UNDO && wParam!=ID_DESC_WND) DiscardUndo();  // discard the previous undo data
  218.  
  219.             switch (COMMAND_ID(wParam,lParam)) {
  220.                 //*********************************************************
  221.                 // Navigation commands                                     
  222.                 //*********************************************************
  223.                 case ID_PGUP:                 // process page-up key 
  224.                     FrWinOrgY-=FrHeight/2;
  225.                     PaintFlag=PAINT_WIN;FrPaint();break;
  226.                 case ID_PGDN:                 // process page-down key 
  227.                     FrWinOrgY+=FrHeight/2;
  228.                     PaintFlag=PAINT_WIN;FrPaint();break;
  229.                 case ID_UP:                   // process the up arrow key 
  230.                     if (SelItem<0 || item[SelItem].type==SECTION) FrWinUp();
  231.                     else FrKeyMove(ID_UP);      // move the item
  232.                     break;
  233.                 case ID_DOWN:                 // process the down arrow key 
  234.                     if (SelItem<0 || item[SelItem].type==SECTION) FrWinDown();
  235.                     else FrKeyMove(ID_DOWN);      // move the item
  236.                     break;
  237.                 case ID_LEFT:                 // process the left arrow 
  238.                     if (SelItem<0 || item[SelItem].type==SECTION) FrWinLeft();
  239.                     else FrKeyMove(ID_LEFT);      // move the item
  240.                     break;
  241.                 case ID_RIGHT:                // process the right arrow 
  242.                     if (SelItem<0 || item[SelItem].type==SECTION) FrWinRight();
  243.                     else FrKeyMove(ID_RIGHT);      // move the item
  244.                     break;
  245.                 
  246.                 //*********************************************************
  247.                 // Edit functions                     
  248.                 //*********************************************************
  249.                 case ID_POS_ITEM:             // position the text inside the item 
  250.                     PosItem();break;
  251.                 case ID_ITEM_OUTLINE:         // edit the item outlines
  252.                     EditItemOutline();break;
  253.                 case ID_ITEM_BACKGROUND:      // edit the item background
  254.                     EditItemBackground();break;
  255.                 case ID_CENTER_ITEM:          // center an item horizontally
  256.                     CenterItem();break;
  257.                 case ID_DEL_ITEM:             // delete the selected item
  258.                     DeleteItem();break;
  259.                 case ID_FONTS:                // display fonts 
  260.                     FrFonts();break;
  261.  
  262.                 case ID_EXPAND_HORZ:         // insert space horizontally
  263.                     ExpandHorizontal();break;
  264.                 case ID_EXPAND_VERT:         // insert space vertically
  265.                     ExpandVertical();break;
  266.                 case ID_COMPRESS_HORZ:       // delete space horizontally
  267.                     CompressHorizontal();break;
  268.                 case ID_COMPRESS_VERT:       // delete space vertically
  269.                     CompressVertical();break;
  270.  
  271.  
  272.                 //*********************************************************
  273.                 // File Menu functions                                            
  274.                 //*********************************************************
  275.                 case  ID_SAVE:               // save the modified text 
  276.                     FrSave(FrFileName);break;
  277.                 case  ID_SAVEAS:             // save the modified text, as user for the file name
  278.                     FrSaveAs(FrFileName);break;
  279.                 case  ID_REP_PARAM:          // accepts report name, page layout, etc options from the users 
  280.                     FrRepParameters();break;
  281.                 case  ID_REP_FILTER:         // accepts record filter for the report 
  282.                     FrRepFilter();break;
  283.                 case  ID_PRINT_OPTIONS:      // accepts printer options from the users 
  284.                     FrPrintOptions();break;
  285.                 case  ID_QUIT:               // quit FORM session 
  286.                     CloseFr();break;
  287.  
  288.                 //********************************************************
  289.                 // Field Functions                                        
  290.                 //********************************************************
  291.                 case ID_INSERT_DATA:         // insert a data field 
  292.                 case ID_INSERT_CALC:         // insert a calculation field 
  293.                 case ID_INSERT_SYS:          // insert a system field 
  294.                 case ID_INSERT_DLG:          // insert a dialog field 
  295.                     InsertFieldPartI(wParam);// begin the field insertion process
  296.                     break;
  297.  
  298.                 case ID_EDIT_FLD:            // edit field attributes 
  299.                     ModifyField();break;
  300.  
  301.                 case ID_EDIT_FLD_EXP:        // edit calculation field expression 
  302.                     EditFieldExp();break;
  303.  
  304.                 case ID_DLG_CREATE:          // create a dialog field 
  305.                     CreateDlgField();break;
  306.                 case ID_DLG_MODIFY:          // modify a dialog field 
  307.                     ModifyDlgField();break;
  308.                 case ID_DLG_DELETE:          // delete a dialog field 
  309.                     DeleteDlgField();break;
  310.  
  311.                 //********************************************************
  312.                 // Section Functions                                      
  313.                 //********************************************************
  314.                 case ID_SEC_NEW:             // create new section 
  315.                     NewSection();break;
  316.                 case ID_SEC_EDIT:            // create new section 
  317.                     EditSection();break;
  318.  
  319.                 case ID_SEC_FILTER:          // Edit section selection crieteria 
  320.                     EditSectionFilter();break;
  321.  
  322.                 case ID_SEC_SORT:            // Edit section sort field 
  323.                     EditSectionSort();break;
  324.                 case ID_SEC_BREAK:           // Edit section break field 
  325.                     EditSectionBreak();break;
  326.  
  327.                 //*********************************************************
  328.                 // Line functions                     
  329.                 //*********************************************************
  330.                 case ID_INSERT_LINE:         // insert a line 
  331.                     InsertLinePartI();break;
  332.                 case ID_EDIT_LINE:           // edit line 
  333.                     EditLine();break;
  334.  
  335.                 //*********************************************************
  336.                 // Label functions                     
  337.                 //*********************************************************
  338.                 case ID_INSERT_LABEL:         // insert a label 
  339.                     InsertLabelPartI();break;
  340.                 case ID_EDIT_LABEL:           // edit a label 
  341.                     if (hDescWnd) {
  342.                        SetFocus(hDescWnd);
  343.                     }
  344.                     break;
  345.  
  346.                 //*********************************************************
  347.                 // Picture functions                     
  348.                 //*********************************************************
  349.                 case  ID_PICT_FROM_CB:        // copy a picture from clipboard 
  350.                 case  ID_PICT_FROM_FILE:      // insert a picture from a bitmap file 
  351.                     InsertPicturePartI(COMMAND_ID(wParam,lParam));break;
  352.                 
  353.                 //*********************************************************
  354.                 // Arrange Menu functions                                        
  355.                 //*********************************************************
  356.                 case ID_ALIGN_HORZ_TOP:      // Align at top edge
  357.                     AlignHorzTop();break;
  358.                 case ID_ALIGN_HORZ_BOT:      // Align at bottom edge
  359.                     AlignHorzBot();break;
  360.                 case ID_ALIGN_HORZ_CENTER:   // Align horizontal at center line.
  361.                     AlignHorzCenter();break;
  362.                 case ID_ALIGN_VERT_LEFT:     // Align at left edge
  363.                     AlignVertLeft();break;
  364.                 case ID_ALIGN_VERT_RIGHT:    // Align at right edge
  365.                     AlignVertRight();break;
  366.                 case ID_ALIGN_VERT_CENTER:   // Align at the vertical center line
  367.                     AlignVertCenter();break;
  368.                 
  369.                 case ID_EVEN_SPACE_HORZ:     // set the equal horizontal space between the items
  370.                     EvenSpaceHorz();break;
  371.                 case ID_EVEN_SPACE_VERT:     // set the equal vertical space between the items
  372.                     EvenSpaceVert();break;
  373.                 
  374.                 case ID_EVEN_SIZE_HORZ:      // set the same width for the selected items
  375.                     EvenSizeHorz();break;
  376.                 case ID_EVEN_SIZE_VERT:      // set the same height for the selected items
  377.                     EvenSizeVert();break;
  378.  
  379.                 case ID_UNDO:                // undo previous arrange command
  380.                     Undo();break;
  381.  
  382.                 //*********************************************************
  383.                 // Miscellaneous functions                                        
  384.                 //*********************************************************
  385.                 case  ID_HELP:               // display help on functions 
  386.                     WinHelp(hWnd,FrHelpFile,HELP_INDEX,0L);
  387.                     break;
  388.  
  389.                 case ID_DESC_WND:            // update label text
  390.                     if (NOTIFY_MSG(wParam,lParam)==EN_KILLFOCUS) UpdateLabelText();
  391.                     break;
  392.  
  393.                 default:
  394.                     return (DefWindowProc(hWnd, message, wParam, lParam));
  395.             }
  396.             break;
  397.  
  398.             //***************************************************************
  399.             // Mouse functions                                               
  400.             //***************************************************************
  401.         case WM_LBUTTONDOWN:                // position or select the object
  402.         case WM_MBUTTONDOWN:                // position or select the object
  403.         case WM_RBUTTONDOWN:                // position or select the object
  404.             FrMouseDown(wParam,lParam);
  405.             break;
  406.  
  407.         case WM_MOUSEMOVE:                   // set highlighted areas 
  408.             if (IgnoreMouseMove) FrSetCursorShape(lParam);
  409.             else FrMouseMove(wParam,lParam);
  410.             break;
  411.  
  412.         case WM_LBUTTONUP:                   // stop stretching highlighted area now 
  413.         case WM_RBUTTONUP: 
  414.         case WM_MBUTTONUP:
  415.             switch (CurCmd) {
  416.                case ID_MOVE_ITEM:
  417.                    MoveItem();break;      // move the selected item
  418.                case ID_SIZE_ITEM:
  419.                    SizeItem();            // resize the selected item
  420.                    DiscardUndo();         // discard unwanted undo
  421.                    break;
  422.                case ID_SELECT_MULTIPLE:   // select multiple items
  423.                    SelectGroupItemPartII();
  424.                    break;
  425.                default:
  426.                    if (CurCmd!=-1 || !DrawOptRect) break;
  427.  
  428.                    // check if any option rectangle has been selected
  429.                    opt=GetMouseOpt(lParam);
  430.                    if      (opt==OPT_LABEL)InsertLabelPartI();
  431.                    else if (opt==OPT_DATA) InsertFieldPartI(ID_INSERT_DATA);
  432.                    else if (opt==OPT_CALC) InsertFieldPartI(ID_INSERT_CALC);
  433.                    else if (opt==OPT_SYS)  InsertFieldPartI(ID_INSERT_SYS);
  434.                    else if (opt==OPT_DLG) {
  435.                       // check if any dialog field available
  436.                       for (i=0;i<MAX_DLGS;i++) if (DlgField[i].InUse) break;
  437.                       if (i<MAX_DLGS)      InsertFieldPartI(ID_INSERT_DLG);
  438.                       else                 CreateDlgField();   // create a dialog field in the dialog table
  439.                    }
  440.                    else if (opt==OPT_LINE) InsertLinePartI();
  441.                    else IgnoreMouseMove=TRUE;
  442.  
  443.                    break;
  444.             }
  445.             break;
  446.  
  447.         case WM_LBUTTONDBLCLK:
  448.             if (CurCmd==-1 && SelItem>=0) {  // modify items
  449.                 if      (item[SelItem].type==LABEL)   EditItemOutline();
  450.                 else if (item[SelItem].type==LINE)    EditLine();
  451.                 else if (item[SelItem].type==FIELD) {
  452.                    if (field[item[SelItem].field].type==TYPE_PICT) EditItemOutline();
  453.                    else                                            ModifyField();
  454.                 }
  455.                 else if (item[SelItem].type==SECTION) EditSection();
  456.             }
  457.             break;
  458.         
  459.         case WM_RBUTTONDBLCLK:
  460.             if (CurCmd==-1 && SelItem>=0) {  // modify items
  461.                 if      (item[SelItem].type==LABEL)   FrFonts();
  462.                 else if (item[SelItem].type==LINE)    EditItemBackground();     
  463.                 else if (item[SelItem].type==FIELD)   {
  464.                    if (field[item[SelItem].field].type==TYPE_PICT) EditItemBackground();
  465.                    else                                            FrFonts();
  466.                 }
  467.                 else if (item[SelItem].type==SECTION) FrRepParameters(); 
  468.             }
  469.             break;
  470.  
  471.         case WM_MBUTTONDBLCLK:               // edit field
  472.             if (CurCmd==-1 && SelItem>=0) EditItemBackground();
  473.             break;
  474.  
  475.         case WM_PAINT:
  476.             RepaintFr();
  477.             break;
  478.  
  479.         case WM_SETFOCUS:
  480.             PaintFlag=PAINT_WIN;                // next time paint the entire client area
  481.             break;
  482.  
  483.         case WM_ENTERIDLE:                      // check if context sensitive help is requested 
  484.             if ((wParam == MSGF_MENU) && (GetKeyState(VK_F1) & 0x8000)) {
  485.                 FrHelpWanted=TRUE;         
  486.                 PostMessage(hWnd,WM_KEYDOWN,VK_RETURN,0L); // generate a dummy <CR> key, cause selection of the menu item 
  487.             }
  488.             break;
  489.  
  490.         case WM_CLOSE:
  491.             CloseFr();
  492.             return (LRESULT)(NULL);
  493.  
  494.         case WM_QUERYENDSESSION:
  495.             return (CloseFr());
  496.  
  497.         case WM_DESTROY:
  498.             FormArg.open=FALSE;                   // mark this window as closed 
  499.             break;
  500.         
  501.         case WM_GETDLGCODE:
  502.             return (long)(DLGC_WANTMESSAGE|DLGC_WANTALLKEYS
  503.                          |DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_WANTTAB);  /* process all messages when REP used as a control */
  504.  
  505.         default:
  506.             return (DefWindowProc(hWnd, message, wParam, lParam));
  507.     }
  508.  
  509.     FormArg.modified=FrModified;         // pass the file status 
  510.  
  511.     return (LRESULT)(NULL);
  512. }
  513.  
  514. /****************************************************************************
  515.     FrEditSubclass:
  516.     This routine subclass the label input edit control to access the
  517.     carriage return key.
  518. ****************************************************************************/
  519. BOOL CALLBACK _export FrEditSubclass(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
  520. {
  521.  
  522.     if (message==WM_CHAR && wParam==VK_RETURN) {
  523.         UpdateLabelText();  // update the label text
  524.         SetFocus(hFrWnd);   // set the focus to the main window
  525.         return TRUE;
  526.     }
  527.     else return (BOOL) CallWindowProc(OrigEditProc,hWnd,message,wParam,lParam);
  528. }
  529.  
  530. /******************************************************************************
  531.     FrInitMenu:
  532.     Initialze the menu before displaying
  533. ******************************************************************************/
  534. FrInitMenu(HMENU hMenu)
  535. {
  536.     int i,CurSec,CurField;
  537.     BOOL DlgTableFull,DlgTableEmpty;
  538.  
  539.     if (SelItem>=0 && item[SelItem].type==FIELD) CurField=item[SelItem].field;
  540.     else                                         CurField=-1;
  541.  
  542.     //****** File Menu *****
  543.     EnableMenuItem(hMenu,ID_PRINT_OPTIONS,PrinterName[0]!=0 ? MF_ENABLED : MF_GRAYED);
  544.     EnableMenuItem(hMenu,ID_SAVE,FrModified ? MF_ENABLED : MF_GRAYED);
  545.  
  546.     //**** Edit Menu ***
  547.     EnableMenuItem(hMenu,ID_FONTS,SelItem>=0 && (item[SelItem].type==LABEL || (item[SelItem].type==FIELD && field[CurField].type!=TYPE_PICT)|| item[SelItem].type==GROUP) ? MF_ENABLED : MF_GRAYED);
  548.     EnableMenuItem(hMenu,ID_POS_ITEM,SelItem>=0 && (item[SelItem].type==LABEL || (item[SelItem].type==FIELD && field[CurField].type!=TYPE_PICT) || item[SelItem].type==GROUP) ? MF_ENABLED : MF_GRAYED);
  549.     EnableMenuItem(hMenu,ID_ITEM_OUTLINE,SelItem>=0 ? MF_ENABLED : MF_GRAYED);
  550.     EnableMenuItem(hMenu,ID_ITEM_BACKGROUND,SelItem>=0 && item[SelItem].type!=PICT? MF_ENABLED : MF_GRAYED);
  551.     EnableMenuItem(hMenu,ID_CENTER_ITEM,SelItem>=0 && item[SelItem].type!=SECTION ? MF_ENABLED : MF_GRAYED);
  552.     EnableMenuItem(hMenu,ID_DEL_ITEM,SelItem>=0 ? MF_ENABLED : MF_GRAYED);
  553.  
  554.     EnableMenuItem(hMenu,ID_EXPAND_HORZ,SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED : MF_GRAYED);
  555.     EnableMenuItem(hMenu,ID_EXPAND_VERT,SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED : MF_GRAYED);
  556.     EnableMenuItem(hMenu,ID_COMPRESS_HORZ,SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED : MF_GRAYED);
  557.     EnableMenuItem(hMenu,ID_COMPRESS_VERT,SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED : MF_GRAYED);
  558.  
  559.     //**** Field Menu ***
  560.     EnableMenuItem(hMenu,ID_EDIT_FLD    ,CurField>=0  && field[CurField].type!=TYPE_PICT ? MF_ENABLED : MF_GRAYED);
  561.     EnableMenuItem(hMenu,ID_EDIT_FLD_EXP,CurField>=0 && field[CurField].source==SRC_CALC ? MF_ENABLED : MF_GRAYED);
  562.  
  563.     //**** section menu Menu ***
  564.     if (SelItem>=0 && item[SelItem].type==SECTION) CurSec=item[SelItem].section;
  565.     else                                           CurSec=-1;        
  566.  
  567.     EnableMenuItem(hMenu,ID_SEC_EDIT,CurSec>=0 ? MF_ENABLED : MF_GRAYED);
  568.     EnableMenuItem(hMenu,ID_SEC_SORT,CurSec>=SEC_HDR_LVL1 && CurSec<=SEC_HDR_LVL9 ? MF_ENABLED : MF_GRAYED);
  569.     EnableMenuItem(hMenu,ID_SEC_BREAK,CurSec>=SEC_HDR_LVL1 && CurSec<=SEC_HDR_LVL9 ? MF_ENABLED : MF_GRAYED);
  570.     EnableMenuItem(hMenu,ID_SEC_FILTER,CurSec>=0 ? MF_ENABLED : MF_GRAYED);
  571.  
  572.     //**** Line Menu ***
  573.     EnableMenuItem(hMenu,ID_EDIT_LINE,SelItem>=0 && item[SelItem].type==LINE ? MF_ENABLED : MF_GRAYED);
  574.     
  575.     //**** Label Menu ***
  576.     EnableMenuItem(hMenu,ID_EDIT_LABEL,SelItem>=0 && item[SelItem].type==LABEL ? MF_ENABLED : MF_GRAYED);
  577.  
  578.     //**** Picture Menu ***
  579.     EnableMenuItem(hMenu,ID_PICT_FROM_CB, IsClipboardFormatAvailable(CF_BITMAP) ? MF_ENABLED : MF_GRAYED);
  580.  
  581.     //******* dialog field table options ******
  582.     DlgTableFull=TRUE;
  583.     DlgTableEmpty=TRUE;
  584.     for (i=0;i<MAX_DLGS;i++) {
  585.        if (DlgField[i].InUse) DlgTableEmpty=FALSE;
  586.        if (!DlgField[i].InUse) DlgTableFull=FALSE;
  587.     }
  588.     EnableMenuItem(hMenu,ID_INSERT_DLG , !DlgTableEmpty ? MF_ENABLED : MF_GRAYED);
  589.     EnableMenuItem(hMenu,ID_DLG_CREATE , !DlgTableFull ? MF_ENABLED : MF_GRAYED);
  590.     EnableMenuItem(hMenu,ID_DLG_MODIFY , !DlgTableEmpty ? MF_ENABLED : MF_GRAYED);
  591.     EnableMenuItem(hMenu,ID_DLG_DELETE , !DlgTableEmpty ? MF_ENABLED : MF_GRAYED);
  592.  
  593.     //**** Arrange Menu ***
  594.     EnableMenuItem(GetSubMenu(hMenu,MENU_ARRANGE),0, SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED|MF_BYPOSITION : MF_GRAYED|MF_BYPOSITION); // align
  595.     EnableMenuItem(GetSubMenu(hMenu,MENU_ARRANGE),1, SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED|MF_BYPOSITION : MF_GRAYED|MF_BYPOSITION); // even space
  596.     EnableMenuItem(GetSubMenu(hMenu,MENU_ARRANGE),2, SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED|MF_BYPOSITION : MF_GRAYED|MF_BYPOSITION); // even size
  597.     EnableMenuItem(hMenu,ID_UNDO, UndoItem ? MF_ENABLED : MF_GRAYED);
  598.  
  599.     return TRUE;
  600. }
  601.  
  602. /******************************************************************************
  603.    FrTranslateAccelerator:
  604.    Translates the accelerator keys for the form editor window
  605. ******************************************************************************/
  606. BOOL FrTranslateAccelerator(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
  607. {
  608.     MSG msg;
  609.  
  610.     if ( message==WM_NCHITTEST || message==WM_MOUSEMOVE 
  611.       || message==WM_SETCURSOR) return FALSE;
  612.  
  613.     if (!hFrAccTable) return FALSE;   // translation table not defined yet 
  614.  
  615.     msg.hwnd=hWnd;                    // fill the message structure 
  616.     msg.message=message;
  617.     msg.wParam=wParam;
  618.     msg.lParam=lParam;
  619.     msg.time=0;
  620.     msg.pt.x=msg.pt.y=0;
  621.  
  622.     if (TranslateAccelerator(hWnd,hFrAccTable,&msg)) {  // accelerator tranlated 
  623.        // remove any messages generated by the TranslateMessage function in WinMain 
  624.        while (PeekMessage(&msg,hWnd,WM_CHAR,WM_CHAR,PM_REMOVE|PM_NOYIELD)); 
  625.        while (PeekMessage(&msg,hWnd,WM_INITMENU,WM_INITMENUPOPUP,PM_REMOVE|PM_NOYIELD)); 
  626.        while (PeekMessage(&msg,hWnd,WM_MENUSELECT,WM_MENUCHAR,PM_REMOVE|PM_NOYIELD)); 
  627.        while (PeekMessage(&msg,hWnd,WM_SYSKEYDOWN,WM_SYSKEYDOWN,PM_REMOVE|PM_NOYIELD)); 
  628.        while (PeekMessage(&msg,hWnd,WM_SYSKEYUP,WM_SYSKEYUP,PM_REMOVE|PM_NOYIELD)); 
  629.        while (PeekMessage(&msg,hWnd,WM_SYSCOMMAND,WM_SYSCOMMAND,PM_REMOVE|PM_NOYIELD)); 
  630.        while (PeekMessage(&msg,hWnd,WM_SYSCHAR,WM_SYSCHAR,PM_REMOVE|PM_NOYIELD)); 
  631.        return TRUE;
  632.     }
  633.     else return FALSE;
  634. }
  635.  
  636. /******************************************************************************
  637.     SetScrollBars:
  638.     Set horizontal and vertical scroll bar positions 
  639. *******************************************************************************/
  640. SetScrollBars()
  641. {
  642.     int ScrollPos;
  643.     
  644.     if (!UseScreen || SessionType=='R') return TRUE;  // window not being used 
  645.  
  646.     if (FrShowVerBar) {   // check for any change in vertical bar status 
  647.        if (FrHeight==0) 
  648.             ScrollPos=0;
  649.        else ScrollPos=VER_SCROLL_MIN+(int)((long)FrWinOrgY*(VER_SCROLL_MAX-VER_SCROLL_MIN)/FrHeight);
  650.        if (ScrollPos!=VerScrollPos) { // redraw 
  651.           VerScrollPos=ScrollPos;
  652.           SetScrollPos(hFrWnd,SB_VERT,VerScrollPos,TRUE);
  653.        }
  654.     }
  655.     if (FrShowHorBar) {   // check for any change in horizontal bar status 
  656.        if (FrWidth==0)
  657.             ScrollPos=0;
  658.        else ScrollPos=HOR_SCROLL_MIN+(int)((long)FrWinOrgX*(HOR_SCROLL_MAX-HOR_SCROLL_MIN)/FrWidth);
  659.        if (ScrollPos!=HorScrollPos) { // redraw 
  660.           HorScrollPos=ScrollPos;
  661.           SetScrollPos(hFrWnd,SB_HORZ,HorScrollPos,TRUE);
  662.        }
  663.     }
  664.     return TRUE;
  665. }
  666.  
  667. /******************************************************************************
  668.     RepaintFr:
  669.     This routine is called when a paint message is received.
  670.     This routine repaint the entire client area.
  671. *******************************************************************************/
  672. RepaintFr()
  673. {
  674.     PAINTSTRUCT PaintData;
  675.  
  676.     BeginPaint(hFrWnd,&PaintData); 
  677.     EndPaint(hFrWnd,&PaintData); 
  678.  
  679.     if (WindowBeingCreated) return TRUE;
  680.  
  681.     GetWinDimension();     // get window dimensions 
  682.  
  683.     PaintFlag=PAINT_WIN;   // paint the entire window
  684.     FrPaint();
  685.     
  686.     return TRUE;
  687. }
  688.  
  689. /******************************************************************************
  690.     GetWinDimension:
  691.     The the following dimensions of the various screen areas.
  692. *******************************************************************************/
  693. void GetWinDimension()
  694. {
  695.     int width,height;
  696.     RECT rect;
  697.  
  698.     //****************** get window dimensions in logical units *********
  699.     GetClientRect(hFrWnd,(LPRECT) &rect);
  700.     width = PixToUnitX(rect.right);
  701.     height = PixToUnitY(rect.bottom);
  702.  
  703.     // *********** calculate input area coordinates *********************
  704.     InputRect.left=0;
  705.     InputRect.top=0; 
  706.     InputRect.right=width;
  707.     InputRect.bottom=InputRect.top+FrFont[DEFAULT_CFMT].height*2;
  708.  
  709.     // *********** calculate ruler area coordinates *********************
  710.     RulerRect.left=0;
  711.     RulerRect.top=InputRect.bottom; 
  712.     RulerRect.right=width;
  713.     if (FormHdr.RulerType==RULER_OFF) 
  714.          RulerRect.bottom=RulerRect.top;
  715.     else RulerRect.bottom=RulerRect.top+FrFont[DEFAULT_CFMT].height + RULER_MARK1_LEN;
  716.  
  717.     // *********** calculate form area coordinates *********************
  718.     FrWinRect.left=0;
  719.     FrWinRect.top=RulerRect.bottom; 
  720.     FrWinRect.right=width;
  721.     FrWinRect.bottom=height;
  722.     if (FrWinRect.bottom<FrWinRect.top) FrWinRect.bottom=FrWinRect.top;
  723.  
  724.     FrWinWidth=FrWinRect.right-FrWinRect.left+1;    // form window width 
  725.     FrWinHeight=FrWinRect.bottom-FrWinRect.top+1;   // form window height 
  726.  
  727.     // ********* calculate form area rectangle in pixel units 
  728.     FrRect.left=UnitToPixX(FrWinRect.left);
  729.     FrRect.right=rect.right;
  730.     FrRect.top=UnitToPixY(FrWinRect.top);
  731.     FrRect.bottom=rect.bottom;
  732.  
  733.     // ******* Create the memory device
  734.     if (hBM) { // delete current bitmap
  735.        SelectObject(hMemDC,hOldBM);
  736.        DeleteObject(hBM);
  737.     }
  738.     if (NULL==(hBM=CreateCompatibleBitmap(hFrDC,rect.right,rect.bottom)) ) {
  739.        AbortFr("Unable to create compatible DC",ERR_DISPLAY);
  740.     }
  741.     hOldBM=SelectObject(hMemDC,hBM);
  742.  
  743.     // set view port origin
  744.     SetViewportOrgEx(hFrDC,FrRect.left,FrRect.top,NULL);  // set view port origins 
  745.     SetViewportOrgEx(hMemDC,FrRect.left,FrRect.top,NULL); // set view port origins 
  746.  
  747. }
  748.  
  749. /******************************************************************************
  750.     FrSetViewWindow:
  751.     Set the portion of the form that will be visible in the view port.
  752. *******************************************************************************/
  753. void FrSetViewWindow()
  754. {
  755.     if (FrWinOrgX<0) FrWinOrgX=0;
  756.     if (FrWinOrgY<0) FrWinOrgY=0;
  757.  
  758.     if (SessionType=='F') {                     // check limit during editing
  759.        if (FrWinOrgX>FrWidth) FrWinOrgX=FrWidth;
  760.        if (FrWinOrgY>FrHeight) FrWinOrgY=FrHeight;
  761.     }
  762.     SetWindowOrgEx(hFrDC,FrWinOrgX,FrWinOrgY,NULL);    // set the logical window origin 
  763.     SetWindowOrgEx(hMemDC,FrWinOrgX,FrWinOrgY,NULL);   // set the logical window origin 
  764.  
  765. }
  766.  
  767. /******************************************************************************
  768.     FrPaint:
  769.     Main FORM window paint routine
  770. *******************************************************************************/
  771. void FrPaint()
  772. {
  773.     RECT rect,iRect;
  774.     HRGN rgn;
  775.     int i;
  776.     BOOL SaveFocusRectDrawn;
  777.  
  778.     if (!PaintEnabled) return;           // painting disabled 
  779.  
  780.     SaveFocusRectDrawn=FocusRectDrawn;   // save the status of the focus rectangle
  781.     FocusRectDrawn=FALSE;                // focus rectangle will be erased
  782.  
  783.     // promote the scope of painting when a section selected
  784.     if (SelItem>=0 && item[SelItem].type==SECTION && PaintFlag!=PAINT_WIN) PaintFlag=PAINT_PARTIAL_WIN;
  785.  
  786.     FrSetViewWindow();                   // set the window origin
  787.     
  788.     // clear the ruler and drawing area
  789.     SelectClipRgn(hMemDC,NULL);           // entire client are enabled for drawing
  790.  
  791.     rect.left=FrWinOrgX;                  // build the drawing area rectangle
  792.     rect.right=rect.left+FrWinWidth;
  793.     rect.top=FrWinOrgY;
  794.     rect.bottom=FrWinOrgY+FrWinHeight;
  795.  
  796.     if (PaintFlag==PAINT_WIN) {           // redraw the whole screen
  797.  
  798.         // clear the input area
  799.         iRect.left=FrWinOrgX;             // build the input area rectangle
  800.         iRect.right=iRect.left+FrWinWidth;
  801.         iRect.top=FrWinOrgY-FrWinRect.top;
  802.         iRect.bottom=iRect.top+(InputRect.bottom-InputRect.top);
  803.         FillRect(hMemDC,&iRect,hInputAreaBrush);
  804.  
  805.         // Clear the ruler and drawing area
  806.         rect.top-=(RulerRect.bottom-RulerRect.top);
  807.         FillRect(hMemDC,&rect,hBackBrush);
  808.  
  809.         rect.top=iRect.top;                // include the input area
  810.         DrawOptRects(hMemDC);              // draw option rectangles
  811.         DrawDividers(hMemDC);              // draw the divider lines
  812.         DrawTopRuler(hMemDC);              // draw the top ruler
  813.     }
  814.     else if (PaintFlag==PAINT_PARTIAL_WIN){// paint the ruler and the drawing area
  815.         rect.top-=(RulerRect.bottom-RulerRect.top);
  816.         FillRect(hMemDC,&rect,hBackBrush);
  817.         DrawDividers(hMemDC);              // draw the divider lines
  818.         DrawTopRuler(hMemDC);              // draw the ruler
  819.     }
  820.     else FillRect(hMemDC,&rect,hBackBrush);// paint just the drawing area
  821.  
  822.     // Set clipping region to include only the drawing area (default mode)
  823.     rgn=CreateRectRgn(FrRect.left,FrRect.top,FrRect.right,FrRect.bottom);
  824.     SelectClipRgn(hMemDC,rgn);
  825.  
  826.     // Draw screen items
  827.     for (i=0;i<TotalItems;i++) DrawItem(hMemDC,i);
  828.     
  829.     // Copy the memory bitmap to the device
  830.     SelectClipRgn(hFrDC,NULL);
  831.     BitBlt(hFrDC,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top,hMemDC,rect.left,rect.top,SRCCOPY);
  832.     
  833.     SelectClipRgn(hFrDC,rgn);
  834.  
  835.     // highlight the selected item
  836.     if (SelItem>=0) SelectItem(SelItem);
  837.     if (SaveFocusRectDrawn || SelItem>=0) FrDrawFocusRect(hFrDC,&CursRect); // redraw the focus rectangle
  838.  
  839.     // reset flags  
  840.     PaintFlag=PAINT_PARTIAL_WIN;         // reset the paint flag
  841.     DeleteObject(rgn);                   // delete the temporary region
  842.     if (FrShowHorBar || FrShowVerBar) SetScrollBars();
  843.  
  844.     ValidateRect(hFrWnd,NULL);           // remove any pending paint messages
  845.  
  846. }
  847.  
  848. /******************************************************************************
  849.     DrawItem:
  850.     Draw the specified item
  851. *******************************************************************************/
  852. void DrawItem(HDC hDC,int CurItem)
  853. {
  854.     RECT rect;
  855.     HPEN hPen;
  856.     HBRUSH hBrush;
  857.  
  858.     //  Do not draw items that are outside the current window
  859.     if (item[CurItem].x>FrWinOrgX+FrWinWidth) return;
  860.     if (item[CurItem].x+item[CurItem].width<FrWinOrgX) return;
  861.     if (item[CurItem].y>FrWinOrgY+FrWinHeight) return;
  862.     if (item[CurItem].y+item[CurItem].height<FrWinOrgY) return;
  863.  
  864.     // build the rectangle
  865.     rect.left=item[CurItem].x;
  866.     rect.right=item[CurItem].x+item[CurItem].width;
  867.     rect.top=item[CurItem].y;
  868.     rect.bottom=item[CurItem].y+item[CurItem].height;
  869.  
  870.     // fill rectangle if needed
  871.     if (item[CurItem].flags&OFLAG_FILL && item[CurItem].type!=GROUP) { // fill rectangle
  872.        if (NULL!=(hBrush=CreateBrushIndirect(&(item[CurItem].brush)))) {
  873.           FillRect(hDC,&rect,hBrush);
  874.           DeleteObject(hBrush);           // delete the temporary brush
  875.        }
  876.     }
  877.  
  878.     // draw the bounding rectangle
  879.     if (item[CurItem].type==GROUP) {     // draw the multiple selection rectangle
  880.        if (CurItem==SelItem) {           // Group item selected
  881.           SelectObject(hDC,hSelectionPen);
  882.           FrDrawRect(hDC,&rect);
  883.        }
  884.     }
  885.     else if (item[CurItem].OutlineSelect) {// draw rectangle
  886.        if (NULL!=(hPen=CreatePen(item[CurItem].OutlineStyle,item[CurItem].OutlineWidth,item[CurItem].OutlineColor))) {
  887.           SelectObject(hDC,hPen);
  888.           FrDrawOutline(hDC,&rect,item[CurItem].OutlineSelect);
  889.           SelectObject(hDC,hFrPen);
  890.           DeleteObject(hPen);             // delete the temporary pen
  891.        }
  892.     }
  893.  
  894.     // draw the item interior
  895.     if (item[CurItem].type==SECTION)      DrawSection(hDC,CurItem);
  896.     else if (item[CurItem].type==LABEL)   DrawLabel(hDC,CurItem);
  897.     else if (item[CurItem].type==FIELD)   DrawField(hDC,CurItem);
  898.     else if (item[CurItem].type==LINE)    DrawLine(hDC,CurItem);
  899.     else if (item[CurItem].type==PICT)    DrawPicture(hDC,CurItem);
  900.  
  901.     // draw focus pen if this item is part of multiple selection item
  902.     if (InGroup(CurItem)) {
  903.        SelectObject(hDC,hFocusPen);
  904.        FrDrawRect(hDC,&rect);
  905.     }
  906.  
  907. }
  908.  
  909. /******************************************************************************
  910.     DrawLabel:
  911.     Draw a label
  912. *******************************************************************************/
  913. void DrawLabel(HDC hDC, int CurItem)
  914. {
  915.     RECT rect;
  916.     int  LabelWidth,LabelHeight,LabelLen,x,y,flags,font;
  917.  
  918.     // build the bounding rectangle
  919.     rect.left=item[CurItem].x;
  920.     rect.right=item[CurItem].x+item[CurItem].width;
  921.     rect.top=item[CurItem].y;
  922.     rect.bottom=item[CurItem].y+item[CurItem].height;
  923.  
  924.     // Get label dimension
  925.     font=item[CurItem].font;
  926.     LabelWidth=GetLabelLen(item[CurItem].label,font);
  927.     LabelHeight=FrFont[font].height;
  928.     LabelLen=lstrlen(item[CurItem].label);
  929.  
  930.     // Get the label position
  931.     flags=item[CurItem].flags;
  932.     if      (flags&OFLAG_HLEFT)  x=rect.left+DESC_MARGIN;
  933.     else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN;
  934.     else                         x=rect.left+(item[CurItem].width-LabelWidth)/2; // center
  935.     if      (flags&OFLAG_VTOP)   y=rect.top;
  936.     else if (flags&OFLAG_VBOTTOM)y=rect.top+(item[CurItem].height-LabelHeight);
  937.     else                         y=rect.top+(item[CurItem].height-LabelHeight)/2; // center
  938.     
  939.     // Draw the label
  940.     SetFont(hDC,(BYTE)font);
  941.     SetTextColor(hDC,item[CurItem].TextColor);
  942.     SetBkMode(hDC,TRANSPARENT);
  943.     if (LabelLen>0) ExtTextOut(hDC,x,y,ETO_CLIPPED,&rect,item[CurItem].label,LabelLen,NULL);
  944.  
  945. }
  946.  
  947. /******************************************************************************
  948.     DrawField:
  949.     Draw a field item
  950. *******************************************************************************/
  951. void DrawField(HDC hDC, int CurItem)
  952. {
  953.     RECT rect;
  954.     int  LabelWidth,LabelHeight,LabelLen,x,y,flags,font;
  955.     struct StrField huge *pField;
  956.     BOOL wrap=FALSE;
  957.  
  958.     pField=&(field[item[CurItem].field]);   // pointer to current field
  959.     
  960.     if (pField->type==TYPE_PICT) return;    // picture field is left empty
  961.     if (pField->type==TYPE_TEXT && (pField->flags)&(FLAG_WRAP|FLAG_WORD_WRAP)) wrap=TRUE;
  962.  
  963.     // build the bounding rectangle
  964.     rect.left=item[CurItem].x;
  965.     rect.right=item[CurItem].x+item[CurItem].width;
  966.     rect.top=item[CurItem].y;
  967.     rect.bottom=item[CurItem].y+item[CurItem].height;
  968.  
  969.     // Get label dimension
  970.     font=item[CurItem].font;
  971.     LabelWidth=GetLabelLen(item[CurItem].label,font);
  972.     LabelHeight=FrFont[font].height;
  973.     LabelLen=lstrlen(item[CurItem].label);
  974.     if (LabelLen==0) return;
  975.  
  976.     // Get the label X position
  977.     flags=item[CurItem].flags;
  978.     if      (flags&OFLAG_HLEFT)  x=rect.left+DESC_MARGIN;
  979.     else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN;
  980.     else                         x=rect.left+(item[CurItem].width-LabelWidth)/2; // center
  981.     
  982.     if (wrap) y=rect.top+(DEF_RECT_HEIGHT-CharHeight)/2-1;
  983.     else {
  984.       if      (flags&OFLAG_VTOP)   y=rect.top;
  985.       else if (flags&OFLAG_VBOTTOM)y=rect.top+(item[CurItem].height-LabelHeight);
  986.       else                         y=rect.top+(item[CurItem].height-LabelHeight)/2; // center
  987.     }
  988.     
  989.     // Draw the label
  990.     SetFont(hDC,(BYTE)font);
  991.     SetTextColor(hDC,item[CurItem].TextColor);
  992.     SetBkMode(hDC,TRANSPARENT);
  993.     if (wrap) {                    // print multiple lines
  994.        while (y+LabelHeight<rect.bottom) {
  995.           ExtTextOut(hDC,x,y,ETO_CLIPPED,&rect,item[CurItem].label,LabelLen,NULL);
  996.           y+=LabelHeight;          // position for the next line
  997.        }
  998.     }
  999.     else ExtTextOut(hDC,x,y,ETO_CLIPPED,&rect,item[CurItem].label,LabelLen,NULL);
  1000.  
  1001. }
  1002.  
  1003. /******************************************************************************
  1004.     DrawLine:
  1005.     Draw a 'line' type item
  1006. *******************************************************************************/
  1007. void DrawLine(HDC hDC, int CurItem)
  1008. {
  1009.     int x1,y1,x2,y2;
  1010.     HPEN hPen;
  1011.  
  1012.     // build the line beginning and ending coordinates
  1013.     if (item[CurItem].LineAngle==ANGLE_HORZ) {        // horizontal line
  1014.        x1=item[CurItem].x;
  1015.        y1=item[CurItem].y+item[CurItem].height/2;
  1016.        x2=x1+item[CurItem].width;
  1017.        y2=y1;
  1018.     }
  1019.     else if (item[CurItem].LineAngle==ANGLE_VERT) {   // vertical line
  1020.        x1=item[CurItem].x+item[CurItem].width/2;
  1021.        y1=item[CurItem].y;
  1022.        x2=x1;
  1023.        y2=y1+item[CurItem].height;
  1024.     }
  1025.     else if (item[CurItem].LineAngle==ANGLE_FDIAG) {  // diagonal line
  1026.        x1=item[CurItem].x;
  1027.        y1=item[CurItem].y;
  1028.        x2=x1+item[CurItem].width;
  1029.        y2=y1+item[CurItem].height;
  1030.     }
  1031.     else {                                            // backword diagonal line
  1032.        x1=item[CurItem].x;
  1033.        y1=item[CurItem].y+item[CurItem].height;
  1034.        x2=x1+item[CurItem].width;
  1035.        y2=item[CurItem].y;
  1036.     }
  1037.  
  1038.     // create the line pen
  1039.     if (NULL!=(hPen=CreatePen(item[CurItem].LineStyle,item[CurItem].LineWidth,item[CurItem].LineColor))) {
  1040.        SelectObject(hDC,hPen);
  1041.  
  1042.        // draw the line
  1043.        MoveToEx(hDC,x1,y1,NULL);
  1044.        LineTo(hDC,x2,y2);
  1045.  
  1046.        SelectObject(hDC,hFrPen);
  1047.        DeleteObject(hPen);             // delete the temporary pen
  1048.     }
  1049.  
  1050. }
  1051.  
  1052. /******************************************************************************
  1053.     DrawPicture:
  1054.     Draw a picture bitmap
  1055. *******************************************************************************/
  1056. void DrawPicture(HDC hDC, int CurItem)
  1057. {
  1058.    HBITMAP hOldBM,hCurBM;
  1059.    int width,height,pict;
  1060.  
  1061.    pict=item[CurItem].font;             // index into the font structure
  1062.    width=FrFont[pict].CharWidth['_'];   // width and height of the picture 
  1063.    height=FrFont[pict].height;
  1064.  
  1065.    hCurBM=FrFont[pict].hBM;
  1066.    if (NULL!=(hOldBM=SelectObject(hPictDC,hCurBM))) {
  1067.       StretchBlt(hDC,item[CurItem].x,item[CurItem].y,item[CurItem].width,item[CurItem].height,hPictDC,0,0,width,height,SRCCOPY);
  1068.       SelectObject(hPictDC,hOldBM);         // deselect the bitmap 
  1069.    }
  1070. }
  1071.  
  1072. /******************************************************************************
  1073.     DrawSection:
  1074.     Draw the specified section boundaries
  1075. *******************************************************************************/
  1076. void DrawSection(HDC hDC,int CurItem)
  1077. {
  1078.     int CurSec,NameLen,NameX,CharCount;
  1079.     RECT rect;
  1080.  
  1081.  
  1082.     // Draw the bounding rectangle for visual aid if section does not have outlines
  1083.     if (!item[CurItem].OutlineSelect) {
  1084.         SelectObject(hDC,hFrPen);              // select default pen 
  1085.         MoveToEx(hDC,item[CurItem].x,item[CurItem].y,NULL);
  1086.         LineTo(hDC,item[CurItem].x+item[CurItem].width,item[CurItem].y);
  1087.         LineTo(hDC,item[CurItem].x+item[CurItem].width,item[CurItem].y+item[CurItem].height);
  1088.         LineTo(hDC,item[CurItem].x,item[CurItem].y+item[CurItem].height);
  1089.         LineTo(hDC,item[CurItem].x,item[CurItem].y);
  1090.     }
  1091.  
  1092.     // build the section banner rectangle
  1093.     CurSec=item[CurItem].section;
  1094.  
  1095.     rect.left=item[CurItem].x;
  1096.     rect.right=item[CurItem].x+item[CurItem].width;
  1097.     rect.top=item[CurItem].y;
  1098.     rect.bottom=item[CurItem].y+FormHdr.SecBannerHeight;
  1099.  
  1100.     if (rect.left<FrWinOrgX) rect.left=FrWinOrgX;
  1101.     if (rect.right>FrWinOrgX+FrWinWidth) rect.right=FrWinOrgX+FrWinWidth;
  1102.     if (rect.right<=rect.left) return;
  1103.     
  1104.     // center the section description
  1105.     NameLen=GetLabelLen(SectionName[CurSec],DEFAULT_CFMT);
  1106.     CharCount=lstrlen(SectionName[CurSec]);
  1107.     NameX=rect.left+(rect.right-rect.left-NameLen)/2;
  1108.     if (NameX<rect.left) CharCount=0;
  1109.     
  1110.     // Select font and print the label
  1111.     SetFont(hDC,DEFAULT_CFMT);
  1112.     SetTextColor(hDC,BackColor);
  1113.     SetBkColor(hDC,DrawColor);
  1114.     ExtTextOut(hDC,NameX,rect.top+(FormHdr.SecBannerHeight-CharHeight)/2,ETO_CLIPPED|ETO_OPAQUE,&rect,SectionName[CurSec],CharCount,NULL);
  1115.     SetTextColor(hDC,DrawColor);           // reset to regular colors
  1116.     SetBkColor(hDC,BackColor);
  1117.  
  1118.     // Draw the left and right rulers
  1119.     if (item[CurItem].x>FrWinOrgX) DrawSideRuler(hDC,TRUE,CurItem);
  1120.     if (item[CurItem].x+item[CurItem].width<FrWinOrgX+FrWinWidth) DrawSideRuler(hDC,FALSE,CurItem);
  1121. }
  1122.  
  1123. /******************************************************************************
  1124.     DrawDividers:
  1125.     Draw the dividers lines for the input and ruler areas
  1126. *******************************************************************************/
  1127. void DrawDividers(HDC hDC)
  1128. {
  1129.     int y;
  1130.  
  1131.     // ******************* select pen **************
  1132.     SelectObject(hDC,hFrPen);       // general purpose pen 
  1133.  
  1134.     // ***************** draw the line above the ruler ***********
  1135.     y=FrWinOrgY-(RulerRect.bottom-RulerRect.top);
  1136.     MoveToEx(hDC,FrWinOrgX,y,NULL);
  1137.     LineTo(hDC,FrWinOrgX+FrWinWidth,y);
  1138.  
  1139.     // ***************** draw the line below the ruler ***********
  1140.     y=FrWinOrgY;
  1141.     MoveToEx(hDC,FrWinOrgX,y,NULL);
  1142.     LineTo(hDC,FrWinOrgX+FrWinWidth,y);
  1143.  
  1144. }
  1145.  
  1146. /******************************************************************************
  1147.     DrawOptRects:
  1148.     Draw the option rectangles
  1149. *******************************************************************************/
  1150. void DrawOptRects(HDC hDC)
  1151. {
  1152.     int i,TotalWidth,LabelWidth,DataWidth,CalcWidth,SysWidth,DlgWidth,LineWidth,
  1153.         FieldWidth,x,TopY,BotY;
  1154.     HBRUSH hBrush;
  1155.  
  1156.  
  1157.     // Get the widths of the option rectangles
  1158.     LabelWidth=GetLabelLen(OPT_LBL_LABEL,DEFAULT_CFMT)+2*DESC_MARGIN;
  1159.     DataWidth=GetLabelLen(OPT_LBL_DATA,DEFAULT_CFMT)+2*DESC_MARGIN;
  1160.     CalcWidth=GetLabelLen(OPT_LBL_CALC,DEFAULT_CFMT)+2*DESC_MARGIN;
  1161.     SysWidth=GetLabelLen(OPT_LBL_SYS,DEFAULT_CFMT)+2*DESC_MARGIN;
  1162.     DlgWidth=GetLabelLen(OPT_LBL_DLG,DEFAULT_CFMT)+2*DESC_MARGIN;
  1163.     LineWidth=GetLabelLen(OPT_LBL_LINE,DEFAULT_CFMT)+2*DESC_MARGIN;
  1164.  
  1165.     FieldWidth=DataWidth+CalcWidth+SysWidth+DlgWidth;
  1166.     TotalWidth=LabelWidth+FieldWidth+LineWidth+CharHeight;
  1167.  
  1168.     // check if we have space for the option rectangle and the input control
  1169.     if (TotalWidth+DESC_WIDTH+CharHeight>FrWinWidth) {
  1170.        DrawOptRect=FALSE;
  1171.        return;
  1172.     }
  1173.     else DrawOptRect=TRUE;
  1174.  
  1175.     // calculate the dimension relative to the window top/left
  1176.     x=FrWinWidth-TotalWidth;       // beginning x position
  1177.     TopY=InputRect.top;
  1178.     BotY=InputRect.bottom;
  1179.  
  1180.     // label rectangle
  1181.     OptRect[OPT_LABEL].top=TopY;
  1182.     OptRect[OPT_LABEL].bottom=BotY;
  1183.     OptRect[OPT_LABEL].left=x;
  1184.     OptRect[OPT_LABEL].right=x=x+LabelWidth;
  1185.  
  1186.     // data field rectangle
  1187.     OptRect[OPT_DATA].top=TopY+CharHeight;
  1188.     OptRect[OPT_DATA].bottom=BotY;
  1189.     OptRect[OPT_DATA].left=x;
  1190.     OptRect[OPT_DATA].right=x=x+DataWidth;
  1191.  
  1192.     // calculation field rectangle
  1193.     OptRect[OPT_CALC].top=TopY+CharHeight;
  1194.     OptRect[OPT_CALC].bottom=BotY;
  1195.     OptRect[OPT_CALC].left=x;
  1196.     OptRect[OPT_CALC].right=x=x+CalcWidth;
  1197.  
  1198.     // system field rectangle
  1199.     OptRect[OPT_SYS].top=TopY+CharHeight;
  1200.     OptRect[OPT_SYS].bottom=BotY;
  1201.     OptRect[OPT_SYS].left=x;
  1202.     OptRect[OPT_SYS].right=x=x+SysWidth;
  1203.  
  1204.     // dialog field rectangle
  1205.     OptRect[OPT_DLG].top=TopY+CharHeight;
  1206.     OptRect[OPT_DLG].bottom=BotY;
  1207.     OptRect[OPT_DLG].left=x;
  1208.     OptRect[OPT_DLG].right=x=x+DlgWidth;
  1209.  
  1210.     // Line rectangle
  1211.     OptRect[OPT_LINE].top=TopY;
  1212.     OptRect[OPT_LINE].bottom=BotY;
  1213.     OptRect[OPT_LINE].left=x;
  1214.     OptRect[OPT_LINE].right=x+LineWidth;
  1215.  
  1216.     // Field label rectangle
  1217.     OptRect[OPT_FIELD].top=TopY;
  1218.     OptRect[OPT_FIELD].bottom=OptRect[OPT_DATA].top;
  1219.     OptRect[OPT_FIELD].left=OptRect[OPT_DATA].left;
  1220.     OptRect[OPT_FIELD].right=OptRect[OPT_DLG].right;
  1221.  
  1222.     // translate the rectangle dimensions to current window origin and draw
  1223.     hBrush=CreateSolidBrush(OptRectColor);
  1224.     SelectObject(hDC,hFrPen);
  1225.     for (i=0;i<MAX_OPTS;i++) {
  1226.        OptRect[i].top=FrWinOrgY+OptRect[i].top-FrWinRect.top;
  1227.        OptRect[i].bottom=FrWinOrgY+OptRect[i].bottom-FrWinRect.top;
  1228.        OptRect[i].left=FrWinOrgX+OptRect[i].left;
  1229.        OptRect[i].right=FrWinOrgX+OptRect[i].right;
  1230.        
  1231.        FillRect(hDC,&OptRect[i],hBrush);
  1232.        FrDrawRect(hDC,&OptRect[i]);
  1233.     }
  1234.     DeleteObject(hBrush);
  1235.  
  1236.     // write the option labels
  1237.     SetFont(hDC,(BYTE)DEFAULT_CFMT);
  1238.     SetTextColor(hDC,BackColor);
  1239.     SetBkMode(hDC,TRANSPARENT);
  1240.     
  1241.     // write the label text
  1242.     ExtTextOut(hDC,OptRect[OPT_LABEL].left+DESC_MARGIN,OptRect[OPT_LABEL].top+CharHeight,ETO_CLIPPED,&OptRect[OPT_LABEL],OPT_LBL_LABEL,lstrlen(OPT_LBL_LABEL),NULL);
  1243.     ExtTextOut(hDC,OptRect[OPT_DATA].left+DESC_MARGIN,OptRect[OPT_DATA].top,ETO_CLIPPED,&OptRect[OPT_DATA],OPT_LBL_DATA,lstrlen(OPT_LBL_DATA),NULL);
  1244.     ExtTextOut(hDC,OptRect[OPT_CALC].left+DESC_MARGIN,OptRect[OPT_CALC].top,ETO_CLIPPED,&OptRect[OPT_CALC],OPT_LBL_CALC,lstrlen(OPT_LBL_CALC),NULL);
  1245.     ExtTextOut(hDC,OptRect[OPT_SYS].left+DESC_MARGIN,OptRect[OPT_SYS].top,ETO_CLIPPED,&OptRect[OPT_SYS],OPT_LBL_SYS,lstrlen(OPT_LBL_SYS),NULL);
  1246.     ExtTextOut(hDC,OptRect[OPT_DLG].left+DESC_MARGIN,OptRect[OPT_DLG].top,ETO_CLIPPED,&OptRect[OPT_DLG],OPT_LBL_DLG,lstrlen(OPT_LBL_DLG),NULL);
  1247.     ExtTextOut(hDC,OptRect[OPT_LINE].left+DESC_MARGIN,OptRect[OPT_LINE].top+CharHeight,ETO_CLIPPED,&OptRect[OPT_LINE],OPT_LBL_LINE,lstrlen(OPT_LBL_LINE),NULL);
  1248.  
  1249.     // write the field header
  1250.     x=OptRect[OPT_FIELD].left+(FieldWidth-GetLabelLen(OPT_LBL_FIELD,DEFAULT_CFMT))/2;
  1251.     ExtTextOut(hDC,x,OptRect[OPT_FIELD].top,ETO_CLIPPED,&OptRect[OPT_FIELD],OPT_LBL_FIELD,lstrlen(OPT_LBL_FIELD),NULL);
  1252.  
  1253. }
  1254.  
  1255. /******************************************************************************
  1256.     DrawTopRuler:
  1257.     Draw the ruler on the top of the window
  1258. *******************************************************************************/
  1259. void DrawTopRuler(HDC hDC)
  1260. {
  1261.     int   y1,y2,count,len;
  1262.     float x,interval;
  1263.     char string[10];
  1264.  
  1265.     if (FormHdr.RulerType==RULER_OFF) return;
  1266.  
  1267.     // ******************* select pen, font, color etc **************
  1268.     SelectObject(hDC,hFrPen);       // general purpose pen 
  1269.     SetFont(hDC,DEFAULT_CFMT);      // use the default font
  1270.     SetTextColor(hDC,DrawColor);
  1271.     SetBkMode(hDC,TRANSPARENT);
  1272.  
  1273.     // ************ Print the ruler line *************************
  1274.     y1=FrWinOrgY-RULER_MARK1_LEN;
  1275.     MoveToEx(hDC,FrWinOrgX,y1,NULL);
  1276.     LineTo(hDC,FrWinOrgX+FrWinWidth,y1);
  1277.  
  1278.     // ***************** draw ruler marks *************************
  1279.     if (FormHdr.RulerType==RULER_INCH) {     // draw inch ruler
  1280.        // draw the inch marks
  1281.        interval=x=(float)UNITS_PER_INCH;
  1282.        y2=FrWinOrgY;
  1283.        count=1;                              // start with one inch
  1284.        while (x<=FrWidth) {
  1285.           MoveToEx(hDC,(int)x,y1,NULL);
  1286.           LineTo(hDC,(int)x,y2);
  1287.           
  1288.           // print inch label
  1289.           wsprintf(string,"%d",count);
  1290.           len=GetLabelLen(string,DEFAULT_CFMT);  // get the length of the label in logical units
  1291.           TextOut(hDC,(int)(x-len/2),y1-CharHeight,string,lstrlen(string));
  1292.  
  1293.           // increment to next inch
  1294.           x+=interval;
  1295.           count++;
  1296.        }
  1297.        // close the ruler
  1298.        MoveToEx(hDC,FrWidth,y1,NULL);
  1299.        LineTo(hDC,FrWidth,y2);
  1300.  
  1301.        // draw the half marks
  1302.        interval=x=(float)UNITS_PER_INCH/2;
  1303.        y2=y1+RULER_MARK2_LEN;
  1304.        while (x<FrWidth) {
  1305.           MoveToEx(hDC,(int)x,y1,NULL);
  1306.           LineTo(hDC,(int)x,y2);
  1307.           x+=interval;
  1308.        }
  1309.  
  1310.        // draw the 1/8 marks
  1311.        interval=x=(float)UNITS_PER_INCH/8;
  1312.        y2=y1+RULER_MARK3_LEN;
  1313.        while (x<FrWidth) {
  1314.           MoveToEx(hDC,(int)x,y1,NULL);
  1315.           LineTo(hDC,(int)x,y2);
  1316.           x+=interval;
  1317.        }
  1318.     }
  1319.     else {                           // draw centimeter ruler
  1320.        // draw the centimeter marks
  1321.        interval=x=((float)UNITS_PER_INCH*10)/25;
  1322.        y2=FrWinOrgY;
  1323.        count=1;                      // start with one cm
  1324.        while (x<=FrWidth) {
  1325.           MoveToEx(hDC,(int)x,y1,NULL);
  1326.           LineTo(hDC,(int)x,y2);
  1327.           
  1328.           // print inch label
  1329.           wsprintf(string,"%d",count);
  1330.           len=GetLabelLen(string,DEFAULT_CFMT);  // get the length of the label in logical units
  1331.           TextOut(hDC,(int)(x-len/2),y1-CharHeight,string,lstrlen(string));
  1332.  
  1333.           // increment to next cm
  1334.           x+=interval;
  1335.           count++;
  1336.        }
  1337.        // close the ruler
  1338.        MoveToEx(hDC,FrWidth,y1,NULL);
  1339.        LineTo(hDC,FrWidth,y2);
  1340.  
  1341.        // draw the half marks
  1342.        interval=x=((float)UNITS_PER_INCH*10)/50;
  1343.        y2=y1+RULER_MARK2_LEN;
  1344.        while (x<FrWidth) {
  1345.           MoveToEx(hDC,(int)x,y1,NULL);
  1346.           LineTo(hDC,(int)x,y2);
  1347.           x+=interval;
  1348.        }
  1349.  
  1350.        // draw the 1/10 marks
  1351.        interval=x=((float)UNITS_PER_INCH*10)/250;
  1352.        y2=y1+RULER_MARK3_LEN;
  1353.        while (x<FrWidth) {
  1354.           MoveToEx(hDC,(int)x,y1,NULL);
  1355.           LineTo(hDC,(int)x,y2);
  1356.           x+=interval;
  1357.        }
  1358.     }
  1359.     return;
  1360. }
  1361.  
  1362. /******************************************************************************
  1363.     DrawSideRuler:
  1364.     Draw the ruler on the left or right side of the given section
  1365. *******************************************************************************/
  1366. void DrawSideRuler(HDC hDC,BOOL left, int CurSec)
  1367. {
  1368.     int   y1,x1,x2,LastY,count,len;
  1369.     float y,interval;
  1370.     char string[10];
  1371.  
  1372.     if (FormHdr.RulerType==RULER_OFF) return;
  1373.  
  1374.     // ******************* select pen, font, color etc **************
  1375.     SelectObject(hDC,hFrPen);       // general purpose pen 
  1376.     SetFont(hDC,DEFAULT_CFMT);      // use the default font
  1377.     SetTextColor(hDC,DrawColor);
  1378.     SetBkMode(hDC,TRANSPARENT);
  1379.  
  1380.     // ************ Print the ruler line *************************
  1381.     if (left) x1=item[CurSec].x-RULER_MARK1_LEN;
  1382.     else      x1=item[CurSec].x+item[CurSec].width+RULER_MARK1_LEN;
  1383.     y1=item[CurSec].y+CharHeight;
  1384.     LastY=item[CurSec].y+item[CurSec].height;      // last y position
  1385.     MoveToEx(hDC,x1,y1,NULL);
  1386.     LineTo(hDC,x1,LastY);
  1387.  
  1388.     // ***************** draw ruler marks *************************
  1389.     if (FormHdr.RulerType==RULER_INCH) {// draw inch ruler
  1390.        // draw the inch marks
  1391.        interval=(float)UNITS_PER_INCH;
  1392.        if (left) x2=item[CurSec].x;  // ending x position
  1393.        else      x2=item[CurSec].x+item[CurSec].width;
  1394.        y=(float)y1;                  // starting y position
  1395.        count=0;                      // start with one inch
  1396.        while (y<=LastY) {
  1397.           MoveToEx(hDC,x1,(int)y,NULL);
  1398.           LineTo(hDC,x2,(int)y);
  1399.           
  1400.           // print inch label
  1401.           wsprintf(string,"%d",count);
  1402.           len=GetLabelLen(string,DEFAULT_CFMT);  // get the length of the label in logical units
  1403.           if (left) TextOut(hDC,x1-len,(int)(y-CharHeight/2),string,lstrlen(string));
  1404.           else      TextOut(hDC,x1,(int)(y-CharHeight/2),string,lstrlen(string));
  1405.  
  1406.           // increment to next inch
  1407.           y+=interval;
  1408.           count++;
  1409.        }
  1410.        // close the ruler
  1411.        MoveToEx(hDC,x1,LastY,NULL);
  1412.        LineTo(hDC,x2,LastY);
  1413.  
  1414.        // draw the half marks
  1415.        interval=(float)UNITS_PER_INCH/2;
  1416.        y=(float)y1+interval;              // starting y position
  1417.        if (left) x2=x1+RULER_MARK2_LEN;
  1418.        else      x2=x1-RULER_MARK2_LEN;
  1419.        while (y<=LastY) {
  1420.           MoveToEx(hDC,x1,(int)y,NULL);
  1421.           LineTo(hDC,x2,(int)y);
  1422.           y+=interval;
  1423.        }
  1424.  
  1425.        // draw the 1/8 marks
  1426.        interval=(float)UNITS_PER_INCH/8;
  1427.        y=(float)y1+interval;              // starting y position
  1428.        if (left) x2=x1+RULER_MARK3_LEN;
  1429.        else      x2=x1-RULER_MARK3_LEN;
  1430.        while (y<=LastY) {
  1431.           MoveToEx(hDC,x1,(int)y,NULL);
  1432.           LineTo(hDC,x2,(int)y);
  1433.           y+=interval;
  1434.        }
  1435.     }
  1436.     else {                           // draw centimeter ruler
  1437.        // draw the centimeter marks
  1438.        interval=((float)UNITS_PER_INCH*(float)10)/25;
  1439.        if (left) x2=item[CurSec].x;  // ending x position
  1440.        else      x2=item[CurSec].x+item[CurSec].width;
  1441.        y=(float)y1;                  // starting y position
  1442.        count=0;                      // start with one inch
  1443.        while (y<=LastY) {
  1444.           MoveToEx(hDC,x1,(int)y,NULL);
  1445.           LineTo(hDC,x2,(int)y);
  1446.           
  1447.           // print inch label
  1448.           wsprintf(string,"%d",count);
  1449.           len=GetLabelLen(string,DEFAULT_CFMT);  // get the length of the label in logical units
  1450.           if (left) TextOut(hDC,x1-len,(int)(y-CharHeight/2),string,lstrlen(string));
  1451.           else      TextOut(hDC,x1,(int)(y-CharHeight/2),string,lstrlen(string));
  1452.  
  1453.           // increment to next cm
  1454.           y+=interval;
  1455.           count++;
  1456.        }
  1457.        // close the ruler
  1458.        MoveToEx(hDC,x1,LastY,NULL);
  1459.        LineTo(hDC,x2,LastY);
  1460.  
  1461.        // draw the half marks
  1462.        interval=((float)UNITS_PER_INCH*(float)10)/50;
  1463.        y=(float)y1+interval;              // starting y position
  1464.        if (left) x2=x1+RULER_MARK2_LEN;
  1465.        else      x2=x1-RULER_MARK2_LEN;
  1466.        while (y<=LastY) {
  1467.           MoveToEx(hDC,x1,(int)y,NULL);
  1468.           LineTo(hDC,x2,(int)y);
  1469.           y+=interval;
  1470.        }
  1471.  
  1472.        // draw the 1/10 marks
  1473.        interval=((float)UNITS_PER_INCH*(float)10)/250;
  1474.        y=(float)y1+interval;              // starting y position
  1475.        if (left) x2=x1+RULER_MARK3_LEN;
  1476.        else      x2=x1-RULER_MARK3_LEN;
  1477.        while (y<=LastY) {
  1478.           MoveToEx(hDC,x1,(int)y,NULL);
  1479.           LineTo(hDC,x2,(int)y);
  1480.           y+=interval;
  1481.        }
  1482.     }
  1483.     return;
  1484. }
  1485.  
  1486. /******************************************************************************
  1487.    InGroup:
  1488.    This routine return TRUE if the specified item is included in the multiple
  1489.    selection group.
  1490. *******************************************************************************/
  1491. BOOL InGroup(int CurItem)
  1492. {
  1493.     RECT GroupRect,CurRect;
  1494.     BOOL inside=TRUE;
  1495.  
  1496.     if (SelItem<0 || item[SelItem].type!=GROUP) return FALSE;  // group not active
  1497.     if (item[CurItem].type==GROUP) return FALSE;  // exclude group item iteself
  1498.     if (item[CurItem].type==SECTION) return FALSE; // exclude the section type items
  1499.  
  1500.     // build the group rectangle
  1501.     GroupRect.left=item[SelItem].x;
  1502.     GroupRect.right=GroupRect.left+item[SelItem].width;
  1503.     GroupRect.top=item[SelItem].y;
  1504.     GroupRect.bottom=GroupRect.top+item[SelItem].height;
  1505.  
  1506.     // build the current item rectangle
  1507.     CurRect.left=item[CurItem].x;
  1508.     CurRect.right=CurRect.left+item[CurItem].width;
  1509.     CurRect.top=item[CurItem].y;
  1510.     CurRect.bottom=CurRect.top+item[CurItem].height;
  1511.  
  1512.     // check if the item falls withing the group rectangle
  1513.     if (CurRect.right<GroupRect.left) inside=FALSE;
  1514.     if (CurRect.left>GroupRect.right) inside=FALSE;
  1515.     if (CurRect.bottom<GroupRect.top) inside=FALSE;
  1516.     if (CurRect.top>GroupRect.bottom) inside=FALSE;
  1517.  
  1518.     if (item[CurItem].flags&OFLAG_SELECT_TOGGLE) inside=!inside;
  1519.  
  1520.     return inside;
  1521. }
  1522.  
  1523. /******************************************************************************
  1524.    SetFont:
  1525.    Select a suitable font for a character format into the display context
  1526. *******************************************************************************/
  1527. SetFont(HDC hDC,unsigned char font)
  1528. {
  1529.     HFONT hFont;
  1530.  
  1531.     if (FrFont[font].IsPict) return TRUE;  // not a true font 
  1532.  
  1533.     hFont=FrFont[font].hFont;
  1534.  
  1535.     SelectObject(hDC,hFont);
  1536.  
  1537.     return TRUE;
  1538. }
  1539.  
  1540. /******************************************************************************
  1541.     FrMouseDown:
  1542.     Select an object, or position a moving object.
  1543. *******************************************************************************/
  1544. FrMouseDown(WPARAM wParam,LPARAM lParam)
  1545. {
  1546.     int i,x,y,CurItem;
  1547.  
  1548.     // calculate logical mouse position 
  1549.     x=FrWinOrgX+PixToUnitX((int)(LOSHORT(lParam))-FrRect.left); 
  1550.     y=FrWinOrgY+PixToUnitY((int)(HISHORT(lParam))-FrRect.top);
  1551.  
  1552.     // check if mouse outside the drawing area
  1553.     if ( HISHORT(lParam)<FrRect.top || y>FrHeight+TAB_HEIGHT/2) { // went outside the drawing area
  1554.        SetCursor(hArrowCursor);
  1555.        CurCmd=-1;                       // no more command being served
  1556.        IgnoreMouseMove=TRUE;            // ignore mouse move now
  1557.        FrEraseFocusRect(hFrDC,&CursRect);
  1558.        FrPaint();
  1559.        return TRUE;
  1560.     }
  1561.  
  1562.     //  Process the command in progress
  1563.     switch (CurCmd) {
  1564.        case ID_INSERT_LABEL:            // insert a label at the current position
  1565.           InsertLabelPartII();          // finish the label creation process
  1566.           break;
  1567.  
  1568.        case ID_INSERT_LINE:             // insert a line at the current position
  1569.           InsertLinePartII();           // finish the line creation process
  1570.           break;
  1571.  
  1572.        case  ID_PICT_FROM_CB:           // insert the clipboard picture at the current position
  1573.        case  ID_PICT_FROM_FILE:         // insert the bitmap file picture at the current position
  1574.           InsertPicturePartII();        // finish the picture insertion process
  1575.           break;
  1576.  
  1577.        case  ID_INSERT_DATA:            // insert data field
  1578.        case  ID_INSERT_CALC:            // insert calculation field
  1579.        case  ID_INSERT_SYS:             // insert system field
  1580.        case  ID_INSERT_DLG:             // insert dialog field
  1581.           InsertFieldPartII();          // finish the field insertion process
  1582.           break;
  1583.  
  1584.        default:
  1585.           if (SelItem>=0) {                         // if on a selected item
  1586.              // Insert or remove this item form group selection
  1587.              if (item[SelItem].type==GROUP && GetKeyState(VK_SHIFT)&0x8000) {
  1588.                  CurItem=GetMouseItem(x,y);        // Get the item selected by the mouse
  1589.                  if (!(item[CurItem].type&(SECTION|GROUP))) {
  1590.                     if (item[CurItem].flags&OFLAG_SELECT_TOGGLE) 
  1591.                          item[CurItem].flags=ResetUintFlag(item[CurItem].flags,OFLAG_SELECT_TOGGLE);
  1592.                     else item[CurItem].flags|=OFLAG_SELECT_TOGGLE;
  1593.                     PaintFlag=PAINT_ITEMS;            // restricted painting
  1594.                     FrPaint();                        // repaint the screen
  1595.                  }
  1596.                  CurCmd=-1;
  1597.                  break;
  1598.              }
  1599.  
  1600.              // Check if a tab on a selected item is clicked
  1601.              for (i=0;i<TotalTabRects;i++) {
  1602.                 if (TabRect[i].left==TabRect[i].right) continue;  // tab not in use
  1603.                 if (  x>=TabRect[i].left && x<TabRect[i].right
  1604.                    && y>=TabRect[i].top  && y<TabRect[i].bottom) break;
  1605.              }
  1606.              if (i<TotalTabRects) {             // size the item
  1607.                  CurTab=i;
  1608.                  if      (CurTab==TAB_NORTH || CurTab==TAB_SOUTH) SetCursor(hVertCursor); 
  1609.                  else if (CurTab==TAB_WEST  || CurTab==TAB_EAST)  SetCursor(hHorzCursor); 
  1610.                  else if (CurTab==TAB_NE    || CurTab==TAB_SW)    SetCursor(hDiagCursor); 
  1611.                  else if (CurTab==TAB_NW    || CurTab==TAB_SE)    SetCursor(hDiagBackCursor); 
  1612.                  CurCmd=ID_SIZE_ITEM;           // initiate the sizing command
  1613.                  IgnoreMouseMove=FALSE;         // now monitor the mouse movement
  1614.              }
  1615.              else {                             // no tab selected
  1616.                  CurItem=GetMouseItem(x,y);     // Get the item selected by the mouse
  1617.                  if (CurItem!=SelItem) {        // new selection
  1618.                     DeselectItem();             // deselect the previous selection
  1619.                     SelItem=CurItem;
  1620.                     PaintFlag=PAINT_ITEMS;      // restricted painting
  1621.                     FrPaint();                  // repaint the screen
  1622.                  }
  1623.                  CurCmd=-1;                      // no command in progress
  1624.                  IgnoreMouseMove=FALSE;          // now monitor the mouse movement
  1625.              }
  1626.           }
  1627.           else {                                // find item to select
  1628.               SelItem=GetMouseItem(x,y);        // Get the item selected by the mouse
  1629.               PaintFlag=PAINT_ITEMS;            // restricted painting
  1630.               FrPaint();                        // repaint the screen
  1631.               CurCmd=-1;
  1632.               IgnoreMouseMove=FALSE;           // now monitor the mouse movement
  1633.           }
  1634.     }
  1635.  
  1636.     return TRUE;
  1637. }
  1638.  
  1639. /******************************************************************************
  1640.     GetMouseItem:
  1641.     This function returns the item number which enclosed the given x and
  1642.     y position.  When more than one item contain the given point, item
  1643.     with smallest area is selected
  1644. *******************************************************************************/
  1645. GetMouseItem(int x,int y)
  1646. {
  1647.    int i,CurItem;
  1648.    long MinArea,ItemArea;
  1649.  
  1650.    // save the mouse position
  1651.    MouseX=x;
  1652.    MouseY=y;
  1653.  
  1654.    // find the item where the mouse is positioned
  1655.    CurItem=-1;
  1656.  
  1657.    for (i=0;i<TotalItems;i++) {
  1658.       if (x<item[i].x || x>item[i].x+item[i].width)  continue;  // outside
  1659.       if (y<item[i].y || y>item[i].y+item[i].height) continue;  // outside
  1660.       if (item[i].type==GROUP && item[i].width<=DESC_MARGIN && item[i].height<=DESC_MARGIN) continue; //no selection
  1661.  
  1662.       // compare the item area
  1663.       ItemArea=(long)item[i].width*(long)item[i].height; // check right side
  1664.       if (ItemArea<0) ItemArea=-ItemArea;
  1665.  
  1666.       if (CurItem<0) {                            // no item selected yet
  1667.          CurItem=i;
  1668.          MinArea=ItemArea;
  1669.       }
  1670.       else if (ItemArea<=MinArea) {// compare with the previously selected item
  1671.          CurItem=i;
  1672.          MinArea=ItemArea;
  1673.       }
  1674.    }
  1675.    
  1676.    if (CurItem<0) CurItem=0;
  1677.    return CurItem;
  1678. }
  1679.  
  1680. /******************************************************************************
  1681.     GetMouseOpt:
  1682.     Get the option rectangle hit by the mouse
  1683. *******************************************************************************/
  1684. GetMouseOpt(DWORD lParam)
  1685. {
  1686.     int i,x,y;
  1687.     HRGN rgn;
  1688.  
  1689.     // calculate logical mouse position 
  1690.     x=FrWinOrgX+PixToUnitX((int)(LOSHORT(lParam))-FrRect.left); 
  1691.     y=FrWinOrgY+PixToUnitY((int)(HISHORT(lParam))-FrRect.top);
  1692.  
  1693.     // find the rectangle that is hit
  1694.     for (i=0;i<MAX_OPTS;i++) {
  1695.        if (x<OptRect[i].left || x>OptRect[i].right)  continue;  // outside
  1696.        if (y<OptRect[i].top || y>OptRect[i].bottom) continue;   // outside
  1697.        break;
  1698.     }
  1699.  
  1700.     // highlight rectangle if a valid option selected
  1701.     if (i<MAX_OPTS-1) {
  1702.        SelectClipRgn(hFrDC,NULL);
  1703.        
  1704.        BitBlt(hFrDC,OptRect[i].left,OptRect[i].top,
  1705.               OptRect[i].right-OptRect[i].left,OptRect[i].bottom-OptRect[i].top,
  1706.               NULL,0,0,DSTINVERT);
  1707.  
  1708.        // reset clipping region to include only the drawing area (default mode)
  1709.        rgn=CreateRectRgn(FrRect.left,FrRect.top,FrRect.right,FrRect.bottom);
  1710.        SelectClipRgn(hFrDC,rgn);
  1711.        DeleteObject(rgn);                   // delete the temporary region
  1712.     }
  1713.  
  1714.     return i;
  1715. }
  1716.  
  1717. /******************************************************************************
  1718.     FrMouseMove:
  1719.     Process the mouse movement.
  1720. *******************************************************************************/
  1721. FrMouseMove(WPARAM wParam,LPARAM lParam)
  1722. {
  1723.     int x,y,width,height;
  1724.     RECT NewRect;
  1725.     BOOL ButtonDown;
  1726.     MSG  msg;
  1727.  
  1728.     // calculate logical mouse position 
  1729.     x=FrWinOrgX+PixToUnitX((int)(LOSHORT(lParam))-FrRect.left); 
  1730.     y=FrWinOrgY+PixToUnitY((int)(HISHORT(lParam))-FrRect.top);
  1731.     ButtonDown=wParam&(MK_LBUTTON|MK_RBUTTON|MK_MBUTTON);  // True when one of the buttons are down
  1732.  
  1733.     // Begin the multiple item selection when mouse clicked in a 'section' type item
  1734.     if (CurCmd==-1) {
  1735.       if (ButtonDown && SelItem>=0) {
  1736.          if (item[SelItem].type==SECTION) return SelectGroupItemPartI(x,y);  // begin multiple item selection
  1737.          else {
  1738.             CurCmd=ID_MOVE_ITEM;             // start moving the selected item
  1739.             x=item[SelItem].x+item[SelItem].width/2;  // set the mouse position
  1740.             y=item[SelItem].y+item[SelItem].height/2; // set the mouse position
  1741.             FrSetCursor(x,y);
  1742.             // remove any pending mouse move messages
  1743.             while (PeekMessage(&msg,hFrWnd,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE|PM_NOYIELD)); 
  1744.             return TRUE;                     // move next time    
  1745.          }
  1746.       }
  1747.       else  return FrSetCursorShape(lParam);   // no action        
  1748.     }
  1749.  
  1750.     // check if mouse outside the drawing area
  1751.     if ( HISHORT(lParam)<FrRect.top) {               // went outside the drawing area
  1752.        SetCursor(hArrowCursor);
  1753.        return TRUE;
  1754.     }
  1755.  
  1756.     // check for any mouse action outside the window
  1757.     if (CurCmd==ID_MOVE_ITEM || CurCmd==ID_SIZE_ITEM || CurCmd==ID_SELECT_MULTIPLE) {
  1758.        if (!ButtonDown) {                           // mouse status not acceptable
  1759.           CurCmd=-1;                                // reset current command
  1760.           IgnoreMouseMove=TRUE;
  1761.           SetCursor(hArrowCursor);
  1762.           return TRUE;
  1763.        }
  1764.     }
  1765.  
  1766.     // Set cursor shape
  1767.     if (CurCmd==ID_SIZE_ITEM) {
  1768.        if      (CurTab==TAB_NORTH || CurTab==TAB_SOUTH) SetCursor(hVertCursor); 
  1769.        else if (CurTab==TAB_WEST  || CurTab==TAB_EAST)  SetCursor(hHorzCursor); 
  1770.        else if (CurTab==TAB_NE    || CurTab==TAB_SW)    SetCursor(hDiagCursor); 
  1771.        else if (CurTab==TAB_NW    || CurTab==TAB_SE)    SetCursor(hDiagBackCursor); 
  1772.     }
  1773.     else if (CurCmd==ID_SELECT_MULTIPLE) SetCursor(hArrowCursor);
  1774.     else SetCursor(hCrossCursor);
  1775.     
  1776.  
  1777.     // Calculate the new cursor position
  1778.     FarMove(&CursRect,&NewRect,sizeof(RECT));
  1779.     if (CurCmd==ID_SIZE_ITEM || CurCmd==ID_SELECT_MULTIPLE) {// object being sized
  1780.         if      (CurTab==TAB_NORTH) NewRect.top=y;
  1781.         else if (CurTab==TAB_SOUTH) NewRect.bottom=y;
  1782.         else if (CurTab==TAB_WEST)  NewRect.left=x;
  1783.         else if (CurTab==TAB_EAST)  NewRect.right=x;
  1784.         else if (CurTab==TAB_NW) {
  1785.            NewRect.left=x;
  1786.            NewRect.top=y;
  1787.         }
  1788.         else if (CurTab==TAB_NW) {
  1789.            NewRect.left=x;
  1790.            NewRect.top=y;
  1791.         }
  1792.         else if (CurTab==TAB_NE) {
  1793.            NewRect.right=x;
  1794.            NewRect.top=y;
  1795.         }
  1796.         else if (CurTab==TAB_SW) {
  1797.            NewRect.left=x;
  1798.            NewRect.bottom=y;
  1799.         }
  1800.         else if (CurTab==TAB_SE) {
  1801.            NewRect.right=x;
  1802.            NewRect.bottom=y;
  1803.         }
  1804.     }
  1805.     else {                                    // object being moved
  1806.         width=CursRect.right-CursRect.left;   // dimension of the current rectangle
  1807.         height=CursRect.bottom-CursRect.top;
  1808.         NewRect.left=x-width/2;
  1809.         NewRect.right=NewRect.left+width;
  1810.         NewRect.top=y-height/2;
  1811.         NewRect.bottom=NewRect.top+height;
  1812.     }
  1813.  
  1814.  
  1815.     // Check if the screen needs to scroll to show the new rectangle
  1816.     if (FrAdjustScroll(&NewRect)) FrSetCursor(x,y);  // set the new mouse poisition
  1817.  
  1818.     // Erase the old rectangle
  1819.     FrEraseFocusRect(hFrDC,&CursRect);
  1820.  
  1821.     // Draw the new focus rectangle
  1822.     FarMove(&NewRect,&CursRect,sizeof(RECT));
  1823.     FrDrawFocusRect(hFrDC,&CursRect);
  1824.  
  1825.     return TRUE;
  1826. }
  1827.  
  1828. /******************************************************************************
  1829.     FrKeyMove:
  1830.     Move the selected item as the arrow keys are pressed.
  1831. *******************************************************************************/
  1832. FrKeyMove(WPARAM wParam)
  1833. {
  1834.     int delta,CurSec,SecItem;
  1835.     RECT rect,SecRect;
  1836.     MSG  msg;
  1837.  
  1838.     if (SelItem<0 || item[SelItem].type==SECTION) return TRUE;
  1839.  
  1840.     // discard any addition key messages
  1841.     while (PeekMessage(&msg,hFrWnd,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE|PM_NOYIELD));;
  1842.     
  1843.     delta=CharHeight/16;     // amount of movement
  1844.           
  1845.     // build the new item position
  1846.     rect.left=item[SelItem].x;
  1847.     rect.top=item[SelItem].y;
  1848.     if      (wParam==ID_UP)    rect.top-=delta;
  1849.     else if (wParam==ID_DOWN)  rect.top+=delta;
  1850.     else if (wParam==ID_LEFT)  rect.left-=delta;
  1851.     else if (wParam==ID_RIGHT) rect.left+=delta;
  1852.     rect.right=rect.left+item[SelItem].width;
  1853.     rect.bottom=rect.top+item[SelItem].height;
  1854.  
  1855.     // make sure that the item remains within the section
  1856.     CurSec=item[SelItem].section;
  1857.     SecItem=section[CurSec].ScrItem;
  1858.     SecRect.top=item[SecItem].y+FormHdr.SecBannerHeight;
  1859.     SecRect.bottom=item[SecItem].y+item[SecItem].height;
  1860.  
  1861.     if (rect.top<=SecRect.top)       return TRUE;  // item heading out
  1862.     if (rect.bottom>=SecRect.bottom) return TRUE;
  1863.  
  1864.     // scroll the screen if necessary
  1865.     FrEraseFocusRect(hFrDC,&CursRect);
  1866.     FarMove(&rect,&CursRect,sizeof(RECT));
  1867.     FrAdjustScroll(&CursRect);
  1868.     MoveItem();                      // move the item to the new location
  1869.  
  1870.     return TRUE;
  1871. }
  1872.  
  1873. /******************************************************************************
  1874.     FrSetCursorShape:
  1875.     The shape of the mouse cursor as it is being moved in the drawing area.
  1876. *******************************************************************************/
  1877. int FrSetCursorShape(DWORD lParam)
  1878. {
  1879.     int i,x,y,CurTab;
  1880.  
  1881.     if (SelItem<0) SetCursor(hArrowCursor);
  1882.     else {       // check if cursor positioned on a tab
  1883.        // calculate logical mouse position 
  1884.        x=FrWinOrgX+PixToUnitX((LOSHORT(lParam))-FrRect.left); 
  1885.        y=FrWinOrgY+PixToUnitY((HISHORT(lParam))-FrRect.top);
  1886.        for (i=0;i<TotalTabRects;i++) {
  1887.           if (TabRect[i].left==TabRect[i].right) continue;  // tab not in use
  1888.           if (  x>=TabRect[i].left && x<TabRect[i].right
  1889.              && y>=TabRect[i].top  && y<TabRect[i].bottom) break;
  1890.        }
  1891.        if (i<TotalTabRects) {             // size the item
  1892.            CurTab=i;
  1893.            if      (CurTab==TAB_NORTH || CurTab==TAB_SOUTH) SetCursor(hVertCursor); 
  1894.            else if (CurTab==TAB_WEST  || CurTab==TAB_EAST)  SetCursor(hHorzCursor); 
  1895.            else if (CurTab==TAB_NE    || CurTab==TAB_SW)    SetCursor(hDiagCursor); 
  1896.            else if (CurTab==TAB_NW    || CurTab==TAB_SE)    SetCursor(hDiagBackCursor); 
  1897.        }
  1898.        else SetCursor(hArrowCursor);
  1899.     }
  1900.     return TRUE;
  1901. }
  1902.  
  1903. /******************************************************************************
  1904.     FrSetCursor:
  1905.     Set the mouse cursor at the specified logical position (x and y).
  1906. *******************************************************************************/
  1907. int FrSetCursor(int x,int y)
  1908. {
  1909.     POINT pt;
  1910.  
  1911.     pt.x=UnitToPixX(x-FrWinOrgX)+FrRect.left;
  1912.     pt.y=UnitToPixY(y-FrWinOrgY)+FrRect.top;
  1913.     ClientToScreen(hFrWnd,&pt);
  1914.     SetCursorPos(pt.x,pt.y);
  1915.  
  1916.     return TRUE;
  1917. }
  1918.  
  1919. /******************************************************************************
  1920.     FrAdjustCursorRect:
  1921.     Adjust the cursor rectangle position such that it completely falls within
  1922.     as section. This function returns the section which contains the item.
  1923. *******************************************************************************/
  1924. int FrAdjustCursorRect()
  1925. {
  1926.     int height,i,SecItem,CurSec,SecTop,SecBottom,temp;
  1927.  
  1928.     // normalize cursor coordinates
  1929.     if (CursRect.top>CursRect.bottom) {
  1930.        temp=CursRect.top;
  1931.        CursRect.top=CursRect.bottom;
  1932.        CursRect.bottom=temp;
  1933.     }
  1934.     if (CursRect.left>CursRect.right) {
  1935.        temp=CursRect.left;
  1936.        CursRect.left=CursRect.right;
  1937.        CursRect.right=temp;
  1938.     }
  1939.  
  1940.     // calculate rectangle height
  1941.     height=CursRect.bottom-CursRect.top;
  1942.  
  1943.     // find the section that includes the cursor rectangle
  1944.     CurSec=-1;
  1945.     for (i=0;i<TotalItems;i++) {
  1946.        if (item[i].type!=SECTION) continue;
  1947.        if (CursRect.top  >=item[i].y && CursRect.top  <=item[i].y+item[i].height) {
  1948.           SecItem=i;
  1949.           CurSec=item[i].section;
  1950.        }
  1951.     }
  1952.     if (CurSec==-1) {        // select the first or the last section
  1953.        if (CursRect.top<0) {  // select the first section
  1954.           for (i=0;i<TotalItems;i++) if (item[i].type==SECTION) break;
  1955.        }
  1956.        else {                // select the last section
  1957.           for (i=TotalItems-1;i>=0;i--) if (item[i].type==SECTION) break;
  1958.        }
  1959.        if (i==TotalItems || i==-1) AbortFr("Error Section Selection",ERR_DISPLAY);
  1960.        SecItem=i;
  1961.        CurSec=item[i].section;
  1962.     }
  1963.  
  1964.     // do not try to fit the selection rectangle within a section
  1965.     if (CurCmd==ID_SELECT_MULTIPLE) return CurSec;
  1966.  
  1967.     // adjust the cursor rectangle if necessary
  1968.     SecTop=item[SecItem].y+FormHdr.SecBannerHeight;  // subtract the banner height
  1969.     SecBottom=item[SecItem].y+item[SecItem].height;
  1970.     
  1971.     if (CursRect.bottom>SecBottom) {
  1972.        CursRect.bottom=SecBottom;
  1973.        CursRect.top=CursRect.bottom-height;
  1974.     }
  1975.     if (CursRect.top<=SecTop) {
  1976.        CursRect.top=SecTop+1;
  1977.        CursRect.bottom=CursRect.top+height;
  1978.        if (CursRect.bottom>SecBottom) CursRect.bottom=SecBottom;
  1979.     }
  1980.  
  1981.     return CurSec;
  1982. }
  1983.  
  1984. /******************************************************************************
  1985.     FrFindItemSlot:
  1986.     This routine returns the sorted position of the cursor rectangle within
  1987.     the item array.  The calling function should provide the section placement
  1988.     of the cursor rectangle.
  1989. *******************************************************************************/
  1990. int FrFindItemSlot(int CurSec)
  1991. {
  1992.     int i;
  1993.  
  1994.     for (i=0;i<TotalItems;i++) {
  1995.        if (item[i].type==SECTION && item[i].section>CurSec) break;  // slot found
  1996.        if (item[i].y<CursRect.top) continue;
  1997.        if (item[i].y>CursRect.top) break;    // slot found
  1998.        if (item[i].x<CursRect.left) continue;
  1999.        break;                                // slot found   
  2000.     }
  2001.     return i;
  2002. }
  2003.  
  2004. /******************************************************************************
  2005.     FrAdjustScroll:
  2006.     If necessary scroll the drawing area to keep the cursor rectangle in view.
  2007.     The first parameter specifies the new location of the cursor rectangle.
  2008.     This function returns a TRUE value if the scrolling was adjusted.
  2009. *******************************************************************************/
  2010. int FrAdjustScroll(RECT far *rect)
  2011. {
  2012.     int width,height,SaveOrg;
  2013.     BOOL paint=FALSE;
  2014.  
  2015.     if (SelItem>=0 && item[SelItem].type==SECTION) return FALSE; // not applicable to sections
  2016.     if (CurCmd==ID_SIZE_ITEM) return FALSE;  
  2017.  
  2018.     // Check the horizontal direction
  2019.     if ( rect->right<=FrWinOrgX
  2020.       || rect->left>=FrWinOrgX+FrWinWidth) {
  2021.         width=rect->right-rect->left;
  2022.         if (width<FrWinWidth) {
  2023.            SaveOrg=FrWinOrgX;
  2024.            FrWinOrgX=rect->left-(FrWinWidth-width)/2;
  2025.            if (FrWinOrgX<0) FrWinOrgX=0;
  2026.            if (FrWinOrgX>FrWidth) FrWinOrgX=FrWidth;
  2027.            if (FrWinOrgX!=SaveOrg) paint=TRUE;
  2028.         }
  2029.     }
  2030.     
  2031.     // Check the vertical direction
  2032.     if ( rect->bottom<=FrWinOrgY
  2033.       || rect->top>=FrWinOrgY+FrWinHeight) {
  2034.          height=rect->bottom-rect->top;
  2035.          if (height<FrWinHeight) {
  2036.             SaveOrg=FrWinOrgY;
  2037.             FrWinOrgY=rect->top-(FrWinHeight-height)/2;
  2038.             if (FrWinOrgY<0) FrWinOrgY=0;
  2039.             if (FrWinOrgY!=SaveOrg) paint=TRUE;
  2040.          }
  2041.     }
  2042.  
  2043.     // refresh the screen
  2044.     if (paint) {
  2045.         PaintFlag=PAINT_WIN;
  2046.         FrPaint();
  2047.         if (FrShowHorBar || FrShowVerBar) SetScrollBars();
  2048.         return TRUE;
  2049.     }
  2050.     else return FALSE;
  2051. }
  2052.  
  2053. /******************************************************************************
  2054.     DeselectItem:
  2055.     Deselect the currently selected item.
  2056. *******************************************************************************/
  2057. int DeselectItem()
  2058. {
  2059.     int i;
  2060.  
  2061.     
  2062.     if (SelItem<0) return TRUE;   // no item selected
  2063.  
  2064.     if (item[SelItem].type==LABEL) UpdateLabelText();  // update the label text for the previous label
  2065.     
  2066.     FrEraseFocusRect(hFrDC,&CursRect); // turnoff the cursor rectangle
  2067.  
  2068.     // erase each tab rectangle
  2069.     for (i=0;i<TotalTabRects;i++) {
  2070.          if (TabRect[i].left==TabRect[i].right) continue; // tab not used
  2071.          FillRect(hFrDC,&TabRect[i],hBackBrush);
  2072.     }
  2073.  
  2074.     if (item[SelItem].type==GROUP) {         // shrink the group item as it is deselected
  2075.         item[SelItem].width=item[SelItem].height=0;
  2076.     }
  2077.  
  2078.     SelItem=-1;
  2079.     TotalTabRects=0;
  2080.  
  2081.     // erase the description window text
  2082.     if (hDescWnd) SetWindowText(hDescWnd,"");
  2083.  
  2084.     return TRUE;
  2085. }
  2086.  
  2087. /******************************************************************************
  2088.     SelectItem:
  2089.     Select the specified item.
  2090. *******************************************************************************/
  2091. int SelectItem(int CurItem)
  2092. {
  2093.    int i,x,y,width,height,fld;
  2094.  
  2095.  
  2096.    FrEraseFocusRect(hFrDC,&CursRect); // turnoff the cursor rectangle
  2097.  
  2098.    SelItem=CurItem;
  2099.    TotalTabRects=MAX_TABS;
  2100.  
  2101.    x=item[CurItem].x;              // item location
  2102.    y=item[CurItem].y;
  2103.    width=item[CurItem].width;      // item width and height
  2104.    height=item[CurItem].height;
  2105.  
  2106.    // Create north tab
  2107.    TabRect[TAB_NORTH].left=x+(width-TAB_WIDTH)/2;
  2108.    TabRect[TAB_NORTH].top=y-TAB_HEIGHT/2;
  2109.  
  2110.    // Create south tab
  2111.    TabRect[TAB_SOUTH].left=x+(width-TAB_WIDTH)/2;
  2112.    TabRect[TAB_SOUTH].top=y+height-TAB_HEIGHT/2;
  2113.  
  2114.    // Create west tab
  2115.    TabRect[TAB_WEST].left=x-TAB_WIDTH/2;
  2116.    TabRect[TAB_WEST].top=y+(height-TAB_HEIGHT)/2;
  2117.  
  2118.    // Create east tab
  2119.    TabRect[TAB_EAST].left=x+width-TAB_WIDTH/2;
  2120.    TabRect[TAB_EAST].top=y+(height-TAB_HEIGHT)/2;
  2121.  
  2122.    // Create north-west tab
  2123.    TabRect[TAB_NW].left=x-TAB_WIDTH/2;
  2124.    TabRect[TAB_NW].top=y-TAB_HEIGHT/2;
  2125.  
  2126.    // Create north-east tab
  2127.    TabRect[TAB_NE].left=x+width-TAB_WIDTH/2;
  2128.    TabRect[TAB_NE].top=y-TAB_HEIGHT/2;
  2129.  
  2130.    // Create south-west tab
  2131.    TabRect[TAB_SW].left=x-TAB_WIDTH/2;
  2132.    TabRect[TAB_SW].top=y+height-TAB_HEIGHT/2;
  2133.  
  2134.    // Create south-east tab
  2135.    TabRect[TAB_SE].left=x+width-TAB_WIDTH/2;
  2136.    TabRect[TAB_SE].top=y+height-TAB_HEIGHT/2;
  2137.  
  2138.    // set the right and bottom coordinates
  2139.    for (i=0;i<TotalTabRects;i++) {
  2140.       // calculate right and bottom coord for the tabs
  2141.       TabRect[i].right=TabRect[i].left+TAB_WIDTH;
  2142.       TabRect[i].bottom=TabRect[i].top+TAB_HEIGHT;
  2143.    } 
  2144.  
  2145.    // Modify tabs for a section item
  2146.    if (item[SelItem].type==SECTION) {
  2147.       for (i=0;i<TotalTabRects;i++) {
  2148.           // Move the north tab below the section banner
  2149.           if (i==TAB_NORTH) {
  2150.              TabRect[i].top=y+FormHdr.SecBannerHeight-TAB_HEIGHT/2;
  2151.              TabRect[i].bottom=TabRect[i].top+TAB_HEIGHT;
  2152.           }
  2153.           // disable all tabs other than north and south
  2154.           if (i!=TAB_NORTH && i!=TAB_SOUTH) {
  2155.             TabRect[i].right=TabRect[i].left;
  2156.             TabRect[i].bottom=TabRect[i].top;
  2157.           }
  2158.       }
  2159.     }
  2160.  
  2161.    // Draw each tab rectangle
  2162.    for (i=0;i<TotalTabRects;i++) {
  2163.         if (TabRect[i].left==TabRect[i].right) continue; // tab not used
  2164.         FillRect(hFrDC,&TabRect[i],hDrawBrush);
  2165.    }
  2166.  
  2167.    // show the selection rectangle
  2168.    CursRect.left=x;
  2169.    CursRect.right=x+width;
  2170.    CursRect.top=y;
  2171.    CursRect.bottom=y+height;
  2172.  
  2173.    // create the description window
  2174.    width=UnitToPixX(DESC_WIDTH);
  2175.    height=UnitToPixY(DESC_HEIGHT);
  2176.    y=UnitToPixY((InputRect.bottom-InputRect.top-DESC_HEIGHT)/2);
  2177.    x=UnitToPixX((InputRect.bottom-InputRect.top-DESC_HEIGHT)/2);
  2178.    if (item[SelItem].type==LABEL) {              // create an edit control
  2179.       if (hDescWnd && DescWndType!=DESC_EDIT) {  // delete the old control
  2180.          DestroyWindow(hDescWnd);
  2181.          hDescWnd=0;
  2182.       }
  2183.       
  2184.       if (!hDescWnd) {                           // create a new edit control window
  2185.          hDescWnd=CreateWindow("EDIT","",WS_CHILD|WS_BORDER|WS_VISIBLE|ES_AUTOHSCROLL,
  2186.          x,y,width,height,hFrWnd,(HMENU)ID_DESC_WND,hFrInst,NULL);
  2187.  
  2188.          // Subclass to access the carriage return key
  2189.          OrigEditProc=(WNDPROC)GetWindowLong(hDescWnd,GWL_WNDPROC);    // original control proceedure
  2190.          SetWindowLong(hDescWnd,GWL_WNDPROC,(DWORD)OurEditProc);
  2191.       }
  2192.  
  2193.       if (hDescWnd) {
  2194.          EnableWindow(hDescWnd,TRUE);
  2195.          DescWndType=DESC_EDIT;
  2196.          SetWindowText(hDescWnd,item[SelItem].label);
  2197.          SendMessage(hDescWnd,WM_PAINT,0,0L);
  2198.       }
  2199.    }
  2200.    else if (item[SelItem].type==FIELD) {         // create an static control
  2201.       if (hDescWnd && DescWndType!=DESC_STATIC) {// delete the old control
  2202.          DestroyWindow(hDescWnd);
  2203.          hDescWnd=0;
  2204.       }
  2205.       if (!hDescWnd) hDescWnd=CreateWindow("STATIC","",WS_CHILD|WS_BORDER|WS_VISIBLE,x,y,width,height,hFrWnd,(HMENU)ID_DESC_WND,hFrInst,NULL);
  2206.       if (hDescWnd) {
  2207.          EnableWindow(hDescWnd,TRUE);
  2208.          DescWndType=DESC_STATIC;
  2209.          fld=item[SelItem].field;
  2210.          SetWindowText(hDescWnd,field[fld].name);
  2211.          SendMessage(hDescWnd,WM_PAINT,0,0L);
  2212.       }
  2213.    }
  2214.    else {                                        // erase any description text
  2215.       if (hDescWnd) {
  2216.          SetWindowText(hDescWnd,"");
  2217.          SendMessage(hDescWnd,WM_PAINT,0,0L);
  2218.          EnableWindow(hDescWnd,FALSE);
  2219.       }
  2220.    }
  2221.  
  2222.    return TRUE;
  2223. }
  2224.  
  2225. /******************************************************************************
  2226.     FrDrawFocusRect:
  2227.     Draw a rectangle of the given dimension using the focus pen.
  2228. ******************************************************************************/
  2229. int FrDrawFocusRect(HDC hDC,RECT far *rect)
  2230. {
  2231.     int SaveRop;
  2232.  
  2233.     if (FocusRectDrawn) return TRUE;     // Focus rectangle already drawn
  2234.  
  2235.     SelectObject(hDC,hFocusPen);
  2236.  
  2237.     SaveRop=SetROP2(hDC,R2_NOTXORPEN);   // Use XOR drawing mode
  2238.     FrDrawRect(hDC,rect);                // draw the rectangle 
  2239.     SetROP2(hDC,SaveRop);                // reset the drawing mode
  2240.     FocusRectDrawn=TRUE;                 // focus rectangle drawn
  2241.  
  2242.     return TRUE;
  2243. }
  2244.  
  2245. /******************************************************************************
  2246.     FrEraseFocusRect:
  2247.     Erase the focus rectangle 
  2248. ******************************************************************************/
  2249. int FrEraseFocusRect(HDC hDC, RECT far *rect)
  2250. {
  2251.     int SaveRop;
  2252.  
  2253.     if (!FocusRectDrawn) return TRUE;
  2254.  
  2255.     SelectObject(hDC,hFocusPen);
  2256.  
  2257.     SaveRop=SetROP2(hDC,R2_NOTXORPEN);   // Use XOR drawing mode
  2258.     FrDrawRect(hDC,rect);                // draw the rectangle 
  2259.     SetROP2(hDC,SaveRop);                // reset the drawing mode
  2260.     FocusRectDrawn=FALSE;                // Focus rectangle no more visible
  2261.  
  2262.     return TRUE;
  2263. }
  2264.  
  2265. /******************************************************************************
  2266.     MarkGroupItems:
  2267.     Mark all the items in the current selection group.  The calling routine
  2268.     should eventually demark these items.
  2269. ******************************************************************************/
  2270. int MarkGroupItems()
  2271. {
  2272.     int i;
  2273.  
  2274.     for (i=0;i<TotalItems;i++) {
  2275.        if (InGroup(i)) item[i].InGroup=TRUE;
  2276.        else            item[i].InGroup=FALSE;
  2277.     }
  2278.     return TRUE;
  2279. }
  2280.  
  2281. /******************************************************************************
  2282.     NextGroupItem:
  2283.     This function return the next item from the selected group of items.
  2284.     The selected item is also excluded from the group.  This function returns
  2285.     -1 if no more items are found in the group
  2286. ******************************************************************************/
  2287. int NextGroupItem()
  2288. {
  2289.     int i;
  2290.  
  2291.     for (i=0;i<TotalItems;i++) if (item[i].InGroup) break;
  2292.     if (i<TotalItems) {
  2293.        item[i].InGroup=FALSE;
  2294.        return i;
  2295.     }
  2296.     else return -1;
  2297. }
  2298.  
  2299. /******************************************************************************
  2300.     LeftMostItem:
  2301.     This function return the left most item from the current group of items.
  2302.     The function return -1 if a group does not have any item.
  2303. ******************************************************************************/
  2304. int LeftMostItem()
  2305. {
  2306.    int i,CurItem,CompVal,MinVal=0;
  2307.  
  2308.    CurItem=-1;
  2309.    for (i=0;i<TotalItems;i++) {
  2310.       if (!item[i].InGroup) continue;
  2311.       CompVal=item[i].x;        // value to be compared
  2312.       if (CurItem<0 || CompVal<MinVal) {
  2313.          CurItem=i;
  2314.          MinVal=CompVal;
  2315.       }
  2316.    }
  2317.    return CurItem;
  2318. }
  2319.  
  2320. /******************************************************************************
  2321.     TopMostItem:
  2322.     This function return the top most item from the current group of items.
  2323.     The function return -1 if a group does not have any item.
  2324. ******************************************************************************/
  2325. int TopMostItem()
  2326. {
  2327.    int i,CurItem,CompVal,MinVal=0;
  2328.  
  2329.    CurItem=-1;
  2330.    for (i=0;i<TotalItems;i++) {
  2331.       if (!item[i].InGroup) continue;
  2332.       CompVal=item[i].y;        // value to be compared
  2333.       if (CurItem<0 || CompVal<MinVal) {
  2334.          CurItem=i;
  2335.          MinVal=CompVal;
  2336.       }
  2337.    }
  2338.    return CurItem;
  2339. }
  2340.  
  2341. /******************************************************************************
  2342.     FrDrawOutline:
  2343.     Draw the specified sides of the given rectangle
  2344. ******************************************************************************/
  2345. int FrDrawOutline(HDC hDC,RECT far *rect,int select)
  2346. {
  2347.     if (select&OUTLINE_LEFT) {    // draw the left side
  2348.        MoveToEx(hDC,rect->left,rect->bottom,NULL);
  2349.        LineTo(hDC,rect->left,rect->top);
  2350.     }
  2351.     if (select&OUTLINE_TOP) {     // draw the top side
  2352.        MoveToEx(hDC,rect->left,rect->top,NULL);
  2353.        LineTo(hDC,rect->right,rect->top);
  2354.     }
  2355.     if (select&OUTLINE_RIGHT) {   // draw the right side
  2356.        MoveToEx(hDC,rect->right,rect->top,NULL);
  2357.        LineTo(hDC,rect->right,rect->bottom);
  2358.     }
  2359.     if (select&OUTLINE_BOT) {     // draw the bottom side
  2360.        MoveToEx(hDC,rect->right,rect->bottom,NULL);
  2361.        LineTo(hDC,rect->left,rect->bottom);
  2362.     }
  2363.  
  2364.     return TRUE;
  2365.  
  2366. /******************************************************************************
  2367.     FrDrawRect:
  2368.     Draw a rectangle of the given dimension using the selected pen.
  2369. ******************************************************************************/
  2370. int FrDrawRect(HDC hDC,RECT far *rect)
  2371. {
  2372.     POINT pt[5];
  2373.  
  2374.     // build points for the rectangle
  2375.     pt[0].x=rect->left;
  2376.     pt[0].y=rect->top;
  2377.     pt[1].x=rect->right;
  2378.     pt[1].y=rect->top;
  2379.     pt[2].x=rect->right;
  2380.     pt[2].y=rect->bottom;
  2381.     pt[3].x=rect->left;
  2382.     pt[3].y=rect->bottom;
  2383.     pt[4].x=rect->left;
  2384.     pt[4].y=rect->top;
  2385.  
  2386.     Polyline(hDC,pt,5);
  2387.     return TRUE;
  2388.  
  2389. /******************************************************************************
  2390.     MakeRect:
  2391.     This routine simply converts x,y,width and height to the RECT structure.
  2392. ******************************************************************************/
  2393. MakeRect(RECT far *rect,int x,int y,int width, int height)
  2394. {
  2395.     rect->left=x;
  2396.     rect->right=x+width;
  2397.     rect->top=y;
  2398.     rect->bottom=y+height;
  2399.     return TRUE;
  2400. }
  2401.  
  2402. /******************************************************************************
  2403.     InitItem:
  2404.     Initialize the specified item structure.
  2405. ******************************************************************************/
  2406. int InitItem(struct StrItem huge *CurItem)
  2407. {
  2408.     CurItem->type=LABEL;            // screen item type: LABEL,FIELD,SECTION,LINE
  2409.     
  2410.     CurItem->x=0;                   // X position of the top/left corner of the object
  2411.     CurItem->y=0;                   // Y position of the top/left coner of the object
  2412.     CurItem->width=0;               // width of the object 
  2413.     CurItem->height=0;              // height of the object
  2414.  
  2415.     CurItem->flags=OFLAG_HLEFT|OFLAG_VCENTER; // Attributes, see OFLAG_ constants 
  2416.     
  2417.     CurItem->font=DEFAULT_CFMT;     // index into font structure for types LABEL or FIELD
  2418.     CurItem->field=0;               // index into 'field' array for type = FIELD
  2419.     CurItem->section=0;             // index into 'section' array for type = SECTION
  2420.     
  2421.     CurItem->label[0]=0;            // label text when type is LABEL
  2422.     CurItem->TextColor=RGB(0,0,0);  // text color
  2423.  
  2424.     CurItem->OutlineSelect=0;       // sides to draw
  2425.     CurItem->OutlineStyle=PS_SOLID; // line style of the bounding rectangle
  2426.     CurItem->OutlineWidth=0;        // line width of the bounding rectangle
  2427.     CurItem->OutlineColor=DrawColor;// line color of the bounding rectangle
  2428.  
  2429.     CurItem->LineAngle=ANGLE_HORZ;  // horizontal line
  2430.     CurItem->LineStyle=PS_SOLID;    // line style of the line type item
  2431.     CurItem->LineWidth=0;           // line width of the line type item
  2432.     CurItem->LineColor=DrawColor;   // line color of the line type item
  2433.  
  2434.     CurItem->brush.lbStyle=BS_SOLID; // brush to paint the bounding rectangle
  2435.     CurItem->brush.lbColor=BackColor;
  2436.     
  2437.     CurItem->sized=FALSE;           // TRUE when manually sized
  2438.  
  2439.     return TRUE;
  2440. }
  2441.  
  2442. /******************************************************************************
  2443.      GetLabelLen:
  2444.      This routine gets the length of a label in logical units.  The second
  2445.      argument specifies the chosen font.
  2446. ******************************************************************************/
  2447. int GetLabelLen(LPSTR label, int font)
  2448. {
  2449.     int len,count;
  2450.     int far *WidthTable,i;
  2451.  
  2452.     count = lstrlen(label);   // number of characters in the label
  2453.  
  2454.     WidthTable=FrFont[font].CharWidth;
  2455.     len=0;                   // length in logical units
  2456.     for (i=0;i<count;i++) len=len+WidthTable[(BYTE)(label[i])];
  2457.  
  2458.     return len;
  2459. }
  2460.  
  2461. /******************************************************************************
  2462.      TruncateText:
  2463.      This routine truncates the text (first argument) to fit within the
  2464.      the specified width. 
  2465. ******************************************************************************/
  2466. TruncateText(LPSTR text, int width, int font)
  2467. {
  2468.     int far *WidthTable,count,len;
  2469.  
  2470.     count = lstrlen(text);   // number of characters in the text
  2471.     WidthTable=FrFont[font].CharWidth;
  2472.  
  2473.     len=0;                   // text length in number of characters
  2474.     
  2475.     while (len<count) {
  2476.        width=width-WidthTable[(BYTE)(text[len])];
  2477.        if (width<0) break;
  2478.        len++;
  2479.     }
  2480.     text[len]=0;              // truncate the field
  2481.  
  2482.     return TRUE;
  2483. }
  2484.  
  2485. /******************************************************************************
  2486.     OurAlloc:
  2487.     Allocate a far memory object of given size. Lock the object, and return
  2488.     the far pointer to the object.
  2489. *******************************************************************************/
  2490. void far *OurAlloc(UINT size) 
  2491. {
  2492.     HGLOBAL hMem;
  2493.  
  2494.     if (NULL==(hMem=GlobalAlloc(GMEM_MOVEABLE, size+1))) AbortFr("Memory Allocation Error (OurAlloc)",1);
  2495.  
  2496.     return (void far *) GlobalLock(hMem);
  2497. }
  2498.  
  2499. /******************************************************************************
  2500.     OurRealloc:
  2501.     Realloc a far memory object to a given size. Lock the object, and return
  2502.     the far pointer to the object.
  2503. *******************************************************************************/
  2504. void far *OurRealloc(void far *pMem,UINT size) 
  2505. {
  2506.     HGLOBAL hMem;
  2507.  
  2508.     #if defined(WIN32)
  2509.        hMem=GlobalHandle(pMem);      // convert pointer to handle
  2510.     #else
  2511.        {
  2512.        DWORD temp=GlobalHandle((UINT)(((DWORD)pMem)>>16));
  2513.        hMem=(HGLOBAL)LOWORD(temp);
  2514.        }
  2515.     #endif
  2516.  
  2517.     GlobalUnlock(hMem);
  2518.  
  2519.     if (NULL==(hMem=GlobalReAlloc(hMem,size+1, 0))) AbortFr("Memory Allocation Error (OurAlloc)",1);
  2520.  
  2521.     return (void far *) GlobalLock(hMem);
  2522. }
  2523.  
  2524. /******************************************************************************
  2525.     OurFree:
  2526.     Free up the given memory object.  This object must have been allocated
  2527.     using the OurAlloc routine.
  2528. *******************************************************************************/
  2529. void OurFree(void far *pMem) 
  2530. {
  2531.     HGLOBAL hMem;
  2532.  
  2533.     if (pMem!=NULL) {
  2534.        #if defined(WIN32)
  2535.           hMem=GlobalHandle(pMem);      // convert pointer to handle
  2536.        #else
  2537.           {
  2538.           DWORD temp=GlobalHandle((UINT)(((DWORD)pMem)>>16));
  2539.           hMem=(HGLOBAL)LOWORD(temp);
  2540.           }
  2541.        #endif
  2542.        GlobalUnlock(hMem);
  2543.        GlobalFree(hMem);
  2544.     }
  2545. }
  2546.  
  2547. /******************************************************************************
  2548.     sAlloc:
  2549.     Replacement of the Winmem package routine. Simply allocates the memory, and 
  2550.     returns the handle as a 32 bit quantity.
  2551. *******************************************************************************/
  2552. DWORD sAlloc(UINT size) 
  2553. {
  2554.  
  2555.     HGLOBAL hMem;
  2556.  
  2557.     if (NULL==(hMem=GlobalAlloc(GMEM_MOVEABLE, size+1))) AbortFr("Memory Allocation Error (OurAlloc)",1);
  2558.  
  2559.     return (DWORD) ((LPSTR)hMem);
  2560. }
  2561.  
  2562. /******************************************************************************
  2563.     sReAlloc:
  2564.     Replacement of the Winmem package routine. Simply reallocates the memory, 
  2565.     and returns the handle as a 32 bit quantity.
  2566. *******************************************************************************/
  2567. DWORD sReAlloc(DWORD hMem,UINT size) 
  2568. {
  2569.     HGLOBAL hGlb;
  2570.  
  2571.     if (NULL==(hGlb=GlobalReAlloc((HGLOBAL)hMem,size+1, 0))) AbortFr("Memory Allocation Error (OurAlloc)",1);
  2572.  
  2573.     return (DWORD) ((LPSTR)hGlb);
  2574. }
  2575.  
  2576. /******************************************************************************
  2577.     sLock:
  2578.     Replacement of the Winmem package routine. Simply locks the global handle 
  2579.     and returns the far pointer.
  2580. *******************************************************************************/
  2581. void far * sLock(DWORD hMem) 
  2582. {
  2583.  
  2584.    return GlobalLock((HGLOBAL)hMem);
  2585. }
  2586.  
  2587. /******************************************************************************
  2588.     sUnlock:
  2589.     Replacement of the Winmem package routine. Simply unlocks the global handle. 
  2590. *******************************************************************************/
  2591. int sUnlock(DWORD hMem) 
  2592. {
  2593.  
  2594.    GlobalUnlock((HGLOBAL)hMem);
  2595.    return TRUE;
  2596. }
  2597.  
  2598. /******************************************************************************
  2599.     sFree:
  2600.     Replacement of the Winmem package routine. Simply frees the global handle.
  2601. *******************************************************************************/
  2602. int sFree(DWORD hMem) 
  2603. {
  2604.  
  2605.    GlobalFree((HGLOBAL)hMem);
  2606.    return TRUE;
  2607. }
  2608.  
  2609.