home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / vibrant / document.c next >
Encoding:
C/C++ Source or Header  |  1996-07-05  |  103.2 KB  |  3,682 lines  |  [TEXT/R*ch]

  1. /*  document.c
  2. * ===========================================================================
  3. *
  4. *                            PUBLIC DOMAIN NOTICE
  5. *            National Center for Biotechnology Information (NCBI)
  6. *
  7. *  This software/database is a "United States Government Work" under the
  8. *  terms of the United States Copyright Act.  It was written as part of
  9. *  the author's official duties as a United States Government employee and
  10. *  thus cannot be copyrighted.  This software/database is freely available
  11. *  to the public for use. The National Library of Medicine and the U.S.
  12. *  Government do not place any restriction on its use or reproduction.
  13. *  We would, however, appreciate having the NCBI and the author cited in
  14. *  any work or product based on this material
  15. *
  16. *  Although all reasonable efforts have been taken to ensure the accuracy
  17. *  and reliability of the software and data, the NLM and the U.S.
  18. *  Government do not and cannot warrant the performance or results that
  19. *  may be obtained by using this software or data. The NLM and the U.S.
  20. *  Government disclaim all warranties, express or implied, including
  21. *  warranties of performance, merchantability or fitness for any particular
  22. *  purpose.
  23. *
  24. * ===========================================================================
  25. *
  26. * File Name:  document.c
  27. *
  28. * Author:  Jonathan Kans
  29. *   
  30. * Version Creation Date: 4/12/93
  31. *
  32. * $Revision: 2.56 $
  33. *
  34. * File Description:  Converts fielded text into final report in a document
  35. *
  36. * Modifications:  
  37. * --------------------------------------------------------------------------
  38. * Date     Name        Description of modification
  39. * -------  ----------  -----------------------------------------------------
  40. *
  41. * 01-25-94 DGG + JK    Fixed MapDocPoint bug
  42. *
  43. * ==========================================================================
  44. */
  45.  
  46. #include <vibrant.h>
  47. #include <document.h>
  48.  
  49. #ifdef COMP_SYMC
  50. #define NULLFONT  0
  51. #else
  52. #define NULLFONT  NULL
  53. #endif
  54.  
  55. /*****************************************************************************
  56. *
  57. *   SYMBOL DEFINES
  58. *
  59. *****************************************************************************/
  60.  
  61. #define JUST_LEFT   0
  62. #define JUST_CENTER 1
  63. #define JUST_RIGHT  2
  64.  
  65. #define MAXLISTS  256
  66. #define LISTSIZE  256
  67. #define MAXFONTS   32
  68.  
  69. /*****************************************************************************
  70. *
  71. *   TYPE DEFINES
  72. *
  73. *****************************************************************************/
  74.  
  75. typedef struct colxdata {
  76.   FonT          font;
  77.   Int2          position;
  78.   Int2          pixWidth;
  79.   Int2          pixInset;
  80.   Int2          charWidth;
  81.   Int2          charInset;
  82.   unsigned int  just      : 2;
  83.   unsigned int  zeroWidth : 1;
  84.   unsigned int  wrap      : 1;
  85.   unsigned int  bar       : 1;
  86.   unsigned int  underline : 1;
  87.   unsigned int  left      : 1;
  88.   unsigned int  last      : 1;
  89. } ColXData, PNTR ColXPtr;
  90.  
  91. typedef struct itemdata {
  92.   DocPrntProc   prtProc;
  93.   Pointer       dataPtr;
  94.   CharPtr       text;
  95.   FonT          font;
  96.   ColXPtr       colFmt;
  97.   VoidPtr       extra;
  98.   Int2          startsAt;
  99.   Int2          numRows;
  100.   Int2          numCols;
  101.   Int2          lineHeight;
  102.   Int2          leadHeight;
  103.   Int2          minLines;
  104.   Int2          minHeight;
  105.   unsigned int  openSpace    : 1;
  106.   unsigned int  keepWithNext : 1;
  107.   unsigned int  keepTogether : 1;
  108.   unsigned int  newPage      : 1;
  109.   unsigned int  tabStops     : 1;
  110.   unsigned int  docOwnsData  : 1;
  111.   unsigned int  notCached    : 1;
  112.   unsigned int  neverCached  : 1;
  113. } ItemData, PNTR ItemPtr;
  114.  
  115. typedef struct listdata {
  116.   ItemData  items [LISTSIZE];
  117. } ListData, PNTR Nlm_ListPtr;
  118.  
  119. typedef struct masterdata {
  120.   Nlm_ListPtr  list [MAXLISTS];
  121. } MasterData, PNTR MasterPtr;
  122.  
  123. typedef struct docdata {
  124.   DoC           doc;
  125.   MasterPtr     master;
  126.   DocDrawProc   draw;
  127.   DocPanProc    pan;
  128.   DocShadeProc  gray;
  129.   DocShadeProc  invert;
  130.   DocShadeProc  color;
  131.   DocPutProc    put;
  132.   DocGetProc    get;
  133.   DocUpdProc    upd;
  134.   VoidPtr       data;
  135.   DocFreeProc   cleanup;
  136.   ValNodePtr    colFmts;
  137.   Int2          numItems;
  138.   Int2          numLines;
  139.   Int2          barmax;
  140.   Int2          tabCount;
  141.   Boolean       autoAdjust;
  142.   Boolean       isvirtual;
  143. } DocData, PNTR Nlm_DocDataPtr;
  144.  
  145. /*****************************************************************************
  146. *
  147. *   justToChar
  148. *       Converts justification parameter to character code
  149. *
  150. *****************************************************************************/
  151.  
  152. static Char  justToChar [4] = {'l', 'c', 'r', 'l'};
  153.  
  154. /*****************************************************************************
  155. *
  156. *   fontHeights
  157. *       Cached list of fonts and font pixel heights
  158. *
  159. *****************************************************************************/
  160.  
  161. static struct fontheights {
  162.   FonT  font;
  163.   Int2  height;
  164. } fontHeights [MAXFONTS];
  165.  
  166. /*****************************************************************************
  167. *
  168. *   GetItemPtr (ddatptr, item)
  169. *       Returns an item pointer given an item number
  170. *
  171. *****************************************************************************/
  172.  
  173. static ItemPtr GetItemPtr (Nlm_DocDataPtr ddatptr, Int2 item)
  174.  
  175. {
  176.   Int2       index;
  177.   Int2       list;
  178.   ItemPtr    itemPtr;
  179.   Nlm_ListPtr    listPtr;
  180.   MasterPtr  masterPtr;
  181.  
  182.   itemPtr = NULL;
  183.   if (ddatptr != NULL && ddatptr->master != NULL && item < ddatptr->numItems) {
  184.     list = (item / LISTSIZE);
  185.     if (list < MAXLISTS) {
  186.       masterPtr = ddatptr->master;
  187.       listPtr = masterPtr->list [list];
  188.       if (listPtr != NULL) {
  189.         index = (item % LISTSIZE);
  190.         itemPtr = &(listPtr->items [index]);
  191.       }
  192.     }
  193.   }
  194.   return itemPtr;
  195. }
  196.  
  197. /*****************************************************************************
  198. *
  199. *   GetItemNum (ddatptr, desired)
  200. *       Returns the number of the item containing the desired line
  201. *
  202. *****************************************************************************/
  203.  
  204. static Int2 GetItemNum (Nlm_DocDataPtr ddatptr, Int2 desired)
  205.  
  206. {
  207.   Boolean  goOn;
  208.   ItemPtr  itemPtr;
  209.   Int2     left;
  210.   Int2     mid;
  211.   Int2     right;
  212.  
  213.   mid = 1;
  214.   if (ddatptr != NULL) {
  215.     left = 1;
  216.     right = ddatptr->numItems;
  217.     goOn = TRUE;
  218.     while (left <= right && goOn) {
  219.       mid = (left + right) / 2;
  220.       itemPtr = GetItemPtr (ddatptr, mid - 1);
  221.       if (itemPtr != NULL) {
  222.         if (desired < itemPtr->startsAt + itemPtr->numRows) {
  223.           right = mid - 1;
  224.         }
  225.         if (desired >= itemPtr->startsAt) {
  226.           left = mid + 1;
  227.         }
  228.       } else {
  229.         goOn = FALSE;
  230.         mid = 1;
  231.       }
  232.     }
  233.   }
  234.   return mid - 1;
  235. }
  236.  
  237. /*****************************************************************************
  238. *
  239. *   GetNextBlock (title, maxwid, byPixels, wordWrap, tabStops, tabCount)
  240. *       Returns the number of characters in the next block, including
  241. *       trailing spaces (which are trimmed back later)
  242. *
  243. *****************************************************************************/
  244.  
  245. static Int2 GetNextBlock (CharPtr title, Int2 maxwid, Boolean byPixels,
  246.                           Boolean wordWrap, Boolean tabStops, Int2 tabCount)
  247.  
  248. {
  249.   Char  ch;
  250.   Int2  i;
  251.   Int2  j;
  252.   Int2  wid;
  253.  
  254.   i = 0;
  255.   j = 0;
  256.   wid = 0;
  257.   if (title != NULL && maxwid > 0) {
  258.     ch = title [i];
  259.     while (ch != '\0' && ch != '\n' && ch != '\r' &&
  260.            (ch != '\t' || tabStops) && wid <= maxwid) {
  261.       if (wordWrap) {
  262.         if (ch == '\t' && tabStops) {
  263.           if (byPixels) {
  264.             wid += CharWidth (' ') * tabCount;
  265.           } else {
  266.             wid += tabCount;
  267.           }
  268.         } else {
  269.           if (byPixels) {
  270.             wid += CharWidth (ch);
  271.           } else {
  272.             wid++;
  273.           }
  274.         }
  275.       }
  276.       i++;
  277.       ch = title [i];
  278.     }
  279.     j = i;
  280.     if (wid > maxwid && wordWrap) {
  281.       j--;
  282.       if (byPixels) {
  283.         while (TextWidth (title, i) > maxwid) {
  284.           i--;
  285.         }
  286.       } else {
  287.         while (i > maxwid) {
  288.           i--;
  289.         }
  290.       }
  291.       while (i > 0 && title [i - 1] != ' ' && title [i - 1] != '-') {
  292.         i--;
  293.       }
  294.       while (title [i] == ' ') {
  295.         i++;
  296.       }
  297.     }
  298.   }
  299.   if (i > 0 && i < j) {
  300.     return i;
  301.   } else if (j > 0) {
  302.     return j;
  303.   } else {
  304.     return 0;
  305.   }
  306. }
  307.  
  308. /*****************************************************************************
  309. *
  310. *   CELL STRUCTURE DEFINITIONS
  311. *
  312. *****************************************************************************/
  313.  
  314. #define CELLCHUNK 128
  315.  
  316. typedef struct celldata {
  317.   Uint2  start;
  318.   Int2   count;
  319. } CellData, PNTR CellPtr;
  320.  
  321. typedef struct parsedata {
  322.   Int2     numCells;
  323.   CellPtr  cellPtr;
  324. } ParseData, PNTR ParsePtr;
  325.  
  326. /*****************************************************************************
  327. *
  328. *   RecordCell (itemPtr, parsePtr, start, len, row, col)
  329. *       Records the character position and length for a given cell
  330. *
  331. *****************************************************************************/
  332.  
  333. static void RecordCell (ItemPtr itemPtr, ParsePtr parsePtr,
  334.                         Uint2 start, Int2 len, Int2 row, Int2 col)
  335.  
  336. {
  337.   Int2     cell;
  338.   CellPtr  cellPtr;
  339.   Int2     newCells;
  340.   Int2     numCells;
  341.  
  342.   if (itemPtr != NULL && parsePtr != NULL && col < itemPtr->numCols) {
  343.     numCells = parsePtr->numCells;
  344.     cellPtr = parsePtr->cellPtr;
  345.     cell = (Int2) ((Int4) row * (Int4) (itemPtr->numCols) + (Int4) col);
  346.     if (cell >= numCells) {
  347.       newCells = (cell / CELLCHUNK + 1) * CELLCHUNK;
  348.       if (cellPtr != NULL) {
  349.         cellPtr = (CellPtr) MemMore (cellPtr, sizeof (CellData) * newCells);
  350.         if (cellPtr != NULL) {
  351.           while (numCells < newCells) {
  352.             cellPtr [numCells].start = 0;
  353.             cellPtr [numCells].count = 0;
  354.             numCells++;
  355.           }
  356.         }
  357.       } else {
  358.         cellPtr = (CellPtr) MemNew (sizeof (CellData) * newCells);
  359.       }
  360.       parsePtr->cellPtr = cellPtr;
  361.       parsePtr->numCells = newCells;
  362.     }
  363.     if (cellPtr != NULL) {
  364.       cellPtr [cell].start = start;
  365.       cellPtr [cell].count = len;
  366.     }
  367.   }
  368. }
  369.  
  370. /*****************************************************************************
  371. *
  372. *   ParseText (itemPtr, parsePtr, text, byPixels, tabCount)
  373. *       Parses text that contains \t, \r and \n characters into a list of
  374. *       cells organized by row and column
  375. *
  376. *****************************************************************************/
  377.  
  378. static void ParseText (ItemPtr itemPtr, ParsePtr parsePtr,
  379.                        CharPtr text, Boolean byPixels, Int2 tabCount)
  380.  
  381. {
  382.   Int2     blklen;
  383.   Char     ch;
  384.   Int2     col;
  385.   ColXPtr  colFmt;
  386.   FonT     curFont;
  387.   FonT     fnt;
  388.   Int2     inset;
  389.   Int2     insetLeft;
  390.   Int2     insetRight;
  391.   Char     just;
  392.   Int2     len;
  393.   Int2     maxwid;
  394.   Int2     numCols;
  395.   Int2     numRows;
  396.   Int2     returnRow;
  397.   Int2     row;
  398.   Uint2    start;
  399.   Int2     tabRow;
  400.   Boolean  tabStops;
  401.   Int2     width;
  402.   Boolean  wrap;
  403.  
  404.   if (itemPtr != NULL && parsePtr != NULL && text != NULL && *text != '\0') {
  405.     colFmt = itemPtr->colFmt;
  406.     if (colFmt != NULL) {
  407.       fnt = itemPtr->font;
  408.       if (byPixels) {
  409.         if (fnt != NULL) {
  410.           SelectFont (fnt);
  411.           curFont = fnt;
  412.         } else {
  413.           SelectFont (systemFont);
  414.           curFont = systemFont;
  415.         }
  416.       }
  417.       start = 0;
  418.       row = 0;
  419.       tabRow = 0;
  420.       returnRow = 1;
  421.       col = 0;
  422.       tabStops = itemPtr->tabStops;
  423.       numRows = 0;
  424.       numCols = itemPtr->numCols;
  425.       while (text [start] != '\0') {
  426.         ch = text [start];
  427.         if (ch != '\0' && ch != '\n' && ch != '\r' && (ch != '\t' || tabStops)) {
  428.           maxwid = INT2_MAX;
  429.           if (col < numCols) {
  430.             if (byPixels) {
  431.               width = colFmt [col].pixWidth;
  432.               inset = colFmt [col].pixInset;
  433.             } else {
  434.               width = colFmt [col].charWidth;
  435.               inset = colFmt [col].charInset;
  436.             }
  437.             just = justToChar [colFmt [col].just];
  438.             wrap = colFmt [col].wrap;
  439.             fnt = colFmt [col].font;
  440.           } else {
  441.             width = 0;
  442.             inset = 0;
  443.             just = 'l';
  444.             wrap = FALSE;
  445.             fnt = NULLFONT;
  446.           }
  447.           if (just == 'c') {
  448.             insetLeft = inset;
  449.             insetRight = inset;
  450.           } else if (just == 'l') {
  451.             insetLeft = inset;
  452.             insetRight = 0;
  453.           } else if (just == 'r') {
  454.             insetLeft = 0;
  455.             insetRight = inset;
  456.           } else {
  457.             insetLeft = 0;
  458.             insetRight = 0;
  459.           }
  460.           if (byPixels) {
  461.             if (col < numCols && wrap && width > 0 &&
  462.                 width >= 2 + insetLeft + insetRight) {
  463.               maxwid = width - 2 - insetLeft - insetRight;
  464.             }
  465.           } else {
  466.             if (col < numCols && wrap && width > 0 &&
  467.                 width >= insetLeft + insetRight) {
  468.               maxwid = width - insetLeft - insetRight;
  469.             }
  470.           }
  471.           if (byPixels) {
  472.             if (fnt != NULL) {
  473.               if (fnt != curFont) {
  474.                 SelectFont (fnt);
  475.                 curFont = fnt;
  476.               }
  477.             } else {
  478.               fnt = itemPtr->font;
  479.               if (fnt != NULL) {
  480.                 if (fnt != curFont) {
  481.                   SelectFont (fnt);
  482.                   curFont = fnt;
  483.                 }
  484.               }
  485.             }
  486.           }
  487.           blklen = GetNextBlock (text + start, maxwid, byPixels,
  488.                                  wrap, tabStops, tabCount);
  489.           len = blklen;
  490.           if (len > 0) {
  491.             if (text [start + len] != '\0') {
  492.               while (len > 0 && text [start + len - 1] == ' ') {
  493.                 len--;
  494.               }
  495.               if (len == 0) {
  496.                 len = blklen;
  497.               }
  498.             }
  499.             RecordCell (itemPtr, parsePtr, start, len, row, col);
  500.             if (len > 0 && col < numCols && colFmt [col].zeroWidth) {
  501.               if (byPixels) {
  502.                 colFmt [col].pixWidth = TextWidth (text + start, len) +
  503.                                         CharWidth (' ') + 2;
  504.               } else {
  505.                 colFmt [col].charWidth = len + 1;
  506.               }
  507.             }
  508.             start += blklen;
  509.           } else {
  510.             if (byPixels) {
  511.               while (TextWidth (text + start, len) <= maxwid) {
  512.                 len++;
  513.               }
  514.             } else {
  515.               while (len <= maxwid) {
  516.                 len++;
  517.               }
  518.             }
  519.             len--;
  520.             if (len > 0) {
  521.               RecordCell (itemPtr, parsePtr, start, len, row, col);
  522.             }
  523.             ch = text [start];
  524.             while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '\t') {
  525.               start++;
  526.               ch = text [start];
  527.             }
  528.           }
  529.         }
  530.         ch = text [start];
  531.         if (ch == '\n') {
  532.           start++;
  533.           row = returnRow;
  534.           tabRow = row;
  535.           returnRow++;
  536.           col = 0;
  537.         } else if (ch == '\r') {
  538.           start++;
  539.           row++;
  540.           returnRow = MAX (returnRow, row + 1);
  541.         } else if (ch == '\t') {
  542.           start++;
  543.           row = tabRow;
  544.           col++;
  545.           if (text [start] == '\0') {
  546.             row = returnRow;
  547.           }
  548.         } else if (ch != '\0' && wrap) {
  549.           if (len == 0) {
  550.             start++;
  551.           }
  552.           row++;
  553.           returnRow = MAX (returnRow, row + 1);
  554.         } else if (ch != '\0') {
  555.           start++;
  556.         } else if (text [start - 1] != '\n' && text [start - 1] != '\r') {
  557.           row = returnRow;
  558.         }
  559.         numRows = MAX (numRows, row);
  560.       }
  561.       itemPtr->numRows = MAX (numRows, itemPtr->minLines);
  562.     }
  563.     SelectFont (systemFont);
  564.   } else if (itemPtr != NULL) {
  565.     itemPtr->numRows = 0;
  566.   }
  567. }
  568.  
  569. /*****************************************************************************
  570. *
  571. *   RearrangeText (itemPtr, parsePtr, text)
  572. *       Reconstructs text in row and column order so that the list of cells
  573. *       does not need to persist
  574. *
  575. *****************************************************************************/
  576.  
  577. static void RearrangeText (ItemPtr itemPtr, ParsePtr parsePtr, CharPtr text)
  578.  
  579. {
  580.   Int2     cell;
  581.   CellPtr  cellPtr;
  582.   Int2     col;
  583.   ColXPtr  colFmt;
  584.   CharPtr  dst;
  585.   Int2     len;
  586.   Int2     minLines;
  587.   Int2     numCells;
  588.   Int2     numCols;
  589.   Int2     numRows;
  590.   Int2     row;
  591.   CharPtr  src;
  592.   CharPtr  str;
  593.  
  594.   if (itemPtr != NULL && parsePtr != NULL && text != NULL && *text != '\0') {
  595.     colFmt = itemPtr->colFmt;
  596.     if (colFmt != NULL) {
  597.       numRows = itemPtr->numRows;
  598.       numCols = itemPtr->numCols;
  599.       minLines = itemPtr->minLines;
  600.       if (parsePtr->numCells > 0 && parsePtr->cellPtr != NULL) {
  601.         cellPtr = parsePtr->cellPtr;
  602.         numCells = parsePtr->numCells;
  603.         len = numRows * numCols;
  604.         for (row = 0; row < numRows; row++) {
  605.           for (col = 0; col < numCols; col++) {
  606.             cell = (Int2) ((Int4) row * (Int4) numCols + (Int4) col);
  607.             if (cell < numCells) {
  608.               len += cellPtr [cell].count;
  609.             }
  610.           }
  611.         }
  612.         str = (CharPtr) MemNew ((Nlm_sizeT) (len + 4 + minLines));
  613.         if (str != NULL) {
  614.           dst = str;
  615.           for (row = 0; row < numRows; row++) {
  616.             for (col = 0; col < numCols; col++) {
  617.               cell = (Int2) ((Int4) row * (Int4) numCols + (Int4) col);
  618.               if (cell < numCells) {
  619.                 if (col > 0) {
  620.                   *dst = '\t';
  621.                   dst++;
  622.                 }
  623.                 src = text + cellPtr [cell].start;
  624.                 len = cellPtr [cell].count;
  625.                 while (len > 0) {
  626.                   *dst = *src;
  627.                   dst++;
  628.                   src++;
  629.                   len--;
  630.                 }
  631.               }
  632.             }
  633.             *dst = '\n';
  634.             dst++;
  635.           }
  636.           while (row < minLines) {
  637.             *dst = '\n';
  638.             dst++;
  639.             row++;
  640.           }
  641.           *dst = '\0';
  642.         }
  643.         itemPtr->text = str;
  644.       }
  645.     }
  646.   }
  647. }
  648.  
  649. /*****************************************************************************
  650. *
  651. *   FormatText (ddatptr, item, itemPtr, byPixels, tabCount)
  652. *       Calls the print function for the item, then parses and rearranges
  653. *       the text so that it can be displayed, saved, or printed
  654. *
  655. *****************************************************************************/
  656.  
  657. static void FormatText (Nlm_DocDataPtr ddatptr, Int2 item, ItemPtr itemPtr,
  658.                         Boolean byPixels, Int2 tabCount)
  659.  
  660. {
  661.   Char       ch;
  662.   Boolean    needToParse;
  663.   Int2       numRows;
  664.   ParseData  parseData;
  665.   CharPtr    text;
  666.  
  667.   if (itemPtr != NULL && itemPtr->text == NULL && itemPtr->prtProc != NULL) {
  668.     needToParse = TRUE;
  669.     if (ddatptr != NULL && ddatptr->get != NULL) {
  670.       text = ddatptr->get (ddatptr->doc, item);
  671.       if (text != NULL) {
  672.         needToParse = FALSE;
  673.       } else {
  674.         text = itemPtr->prtProc (ddatptr->doc, item, itemPtr->dataPtr);
  675.       }
  676.     } else if (ddatptr != NULL) {
  677.       text = itemPtr->prtProc (ddatptr->doc, item, itemPtr->dataPtr);
  678.     }
  679.     if (needToParse && text != NULL && *text != '\0') {
  680.       parseData.numCells = 0;
  681.       parseData.cellPtr = NULL;
  682.       ParseText (itemPtr, &parseData, text, byPixels, tabCount);
  683.       RearrangeText (itemPtr, &parseData, text);
  684.       itemPtr->notCached = FALSE;
  685.       itemPtr->neverCached = FALSE;
  686.       MemFree (text);
  687.       MemFree (parseData.cellPtr);
  688.     } else {
  689.       itemPtr->text = text;
  690.     }
  691.     text = itemPtr->text;
  692.     if (text == NULL || *text == '\0') {
  693.       MemFree (itemPtr->text);
  694.       itemPtr->text = StringSave (" \n");
  695.       itemPtr->numRows = 1;
  696.       itemPtr->notCached = FALSE;
  697.       itemPtr->neverCached = FALSE;
  698.       needToParse = TRUE;
  699.     } else if (ddatptr != NULL && ddatptr->isvirtual) {
  700.       numRows = 0;
  701.       ch = *text;
  702.       while (ch != '\0') {
  703.         if (ch == '\n') {
  704.           numRows++;
  705.         }
  706.         text++;
  707.         ch = *text;
  708.       }
  709.       numRows = MAX (1, numRows);
  710.       itemPtr->numRows = MAX (numRows, itemPtr->minLines);
  711.     }
  712.     if (needToParse && ddatptr != NULL && ddatptr->put != NULL) {
  713.       ddatptr->put (ddatptr->doc, item, itemPtr->text);
  714.     }
  715.   }
  716. }
  717.  
  718. /*****************************************************************************
  719. *
  720. *   GetStartsAt (ddatptr, item)
  721. *       Returns the first line of the item
  722. *
  723. *****************************************************************************/
  724.  
  725. static Int2 GetStartsAt (Nlm_DocDataPtr ddatptr, Int2 item)
  726.  
  727. {
  728.   Int2     startsAt;
  729.   ItemPtr  itemPtr;
  730.  
  731.   startsAt = 0;
  732.   if (ddatptr != NULL) {
  733.     itemPtr = GetItemPtr (ddatptr, item);
  734.     if (itemPtr != NULL) {
  735.       startsAt = itemPtr->startsAt;
  736.     }
  737.   }
  738.   return startsAt;
  739. }
  740.  
  741. /*****************************************************************************
  742. *
  743. *   GetNumRows (ddatptr, item)
  744. *       Returns the number of rows in the item
  745. *
  746. *****************************************************************************/
  747.  
  748. static Int2 GetNumRows (Nlm_DocDataPtr ddatptr, Int2 item)
  749.  
  750. {
  751.   ItemPtr  itemPtr;
  752.   Int2     numLines;
  753.  
  754.   numLines = 0;
  755.   if (ddatptr != NULL) {
  756.     itemPtr = GetItemPtr (ddatptr, item);
  757.     if (itemPtr != NULL) {
  758.       numLines = itemPtr->numRows;
  759.     }
  760.   }
  761.   return numLines;
  762. }
  763.  
  764. /*****************************************************************************
  765. *
  766. *   GetLineHeight (ddatptr, item)
  767. *       Returns the pixel height of the item
  768. *
  769. *****************************************************************************/
  770.  
  771. static Int2 GetLineHeight (Nlm_DocDataPtr ddatptr, Int2 item)
  772.  
  773. {
  774.   ItemPtr  itemPtr;
  775.   Int2     lineHeight;
  776.  
  777.   lineHeight = 0;
  778.   if (ddatptr != NULL) {
  779.     itemPtr = GetItemPtr (ddatptr, item);
  780.     if (itemPtr != NULL) {
  781.       lineHeight = itemPtr->lineHeight;
  782.     }
  783.   }
  784.   return lineHeight;
  785. }
  786.  
  787. /*****************************************************************************
  788. *
  789. *   SetTablePixFormat (colFmt, left, numCols)
  790. *       Uses pixel widths to calculate the positions of columns for drawing
  791. *
  792. *****************************************************************************/
  793.  
  794. static void SetTablePixFormat (ColXPtr colFmt, Int2 left, Int2 numCols)
  795.  
  796. {
  797.   Int2  i;
  798.  
  799.   if (colFmt != NULL) {
  800.     colFmt [0].position = left;
  801.     for (i = 1; i < numCols; i++) {
  802.       if (colFmt [i].left) {
  803.         colFmt [i].position = left;
  804.       } else {
  805.         colFmt [i].position = colFmt [i - 1].position + colFmt [i - 1].pixWidth;
  806.       }
  807.     }
  808.   }
  809. }
  810.  
  811. /*****************************************************************************
  812. *
  813. *   SetTableCharFormat (colFmt, numCols)
  814. *       Uses character counts to calculate the positions of columns for saving
  815. *
  816. *****************************************************************************/
  817.  
  818. static void SetTableCharFormat (ColXPtr colFmt, Int2 numCols)
  819.  
  820. {
  821.   Int2  i;
  822.  
  823.   if (colFmt != NULL) {
  824.     colFmt [0].position = 0;
  825.     for (i = 1; i < numCols; i++) {
  826.       if (colFmt [i].left) {
  827.         colFmt [i].position = 0;
  828.       } else {
  829.         colFmt [i].position = colFmt [i - 1].position + colFmt [i - 1].charWidth;
  830.       }
  831.     }
  832.   }
  833. }
  834.  
  835. /*****************************************************************************
  836. *
  837. *   UpdateLineStarts (ddatptr, frst)
  838. *       Recalculates the first lines as a running sum of the number of rows
  839. *
  840. *****************************************************************************/
  841.  
  842. static Int2 UpdateLineStarts (Nlm_DocDataPtr ddatptr, Int2 frst)
  843.  
  844. {
  845.   Int2     i;
  846.   ItemPtr  itemPtr;
  847.   Int2     totalNumLines;
  848.  
  849.   totalNumLines = 0;
  850.   if (ddatptr != NULL) {
  851.     itemPtr = GetItemPtr (ddatptr, frst);
  852.     if (itemPtr != NULL) {
  853.       totalNumLines = itemPtr->startsAt;
  854.     }
  855.     for (i = frst; i < ddatptr->numItems; i++) {
  856.       itemPtr = GetItemPtr (ddatptr, i);
  857.       if (itemPtr != NULL) {
  858.         itemPtr->startsAt = totalNumLines;
  859.         totalNumLines += itemPtr->numRows;
  860.       }
  861.     }
  862.   }
  863.   return totalNumLines;
  864. }
  865.  
  866. /*****************************************************************************
  867. *
  868. *   CollectRange (item, lowest, highest)
  869. *       Records the range of items that were manipulated for the purpose of
  870. *       updating line starts or uncaching formatted text on items that are
  871. *       not currently visible
  872. *
  873. *****************************************************************************/
  874.  
  875. static void CollectRange (Int2 item, Int2Ptr lowest, Int2Ptr highest)
  876.  
  877. {
  878.   if (lowest != NULL) {
  879.     *lowest = MIN (*lowest, item);
  880.   }
  881.   if (highest != NULL) {
  882.     *highest = MAX (*highest, item);
  883.   }
  884. }
  885.  
  886. /*****************************************************************************
  887. *
  888. *   CacheAndFormat (ddatptr, item, itemPtr, r, tabCount)
  889. *       Formats text (for drawing) if the item text is not currently cached
  890. *
  891. *****************************************************************************/
  892.  
  893. static void CacheAndFormat (Nlm_DocDataPtr ddatptr, Int2 item, ItemPtr itemPtr,
  894.                             RectPtr r, Int2 tabCount)
  895.  
  896. {
  897.   if (itemPtr != NULL && r != NULL && itemPtr->notCached) {
  898.     SetTablePixFormat (itemPtr->colFmt, r->left, itemPtr->numCols);
  899.     FormatText (ddatptr, item, itemPtr, TRUE, tabCount);
  900.   }
  901. }
  902.  
  903. /*****************************************************************************
  904. *
  905. *   CacheIfNever (ddatptr, item, itemPtr, r, tabCount)
  906. *       Formats text (for obtaining the correct number of rows) if the item
  907. *       text has never been cached
  908. *
  909. *****************************************************************************/
  910.  
  911. static void CacheIfNever (Nlm_DocDataPtr ddatptr, Int2 item, ItemPtr itemPtr,
  912.                           RectPtr r, Int2 tabCount)
  913.  
  914. {
  915.   if (itemPtr != NULL && r != NULL && itemPtr->neverCached) {
  916.     SetTablePixFormat (itemPtr->colFmt, r->left, itemPtr->numCols);
  917.     FormatText (ddatptr, item, itemPtr, TRUE, tabCount);
  918.   }
  919. }
  920.  
  921. /*****************************************************************************
  922. *
  923. *   FreeCachedItem (ddatptr, item, lowest, highest)
  924. *       Frees the formatted text string for an item that is not currently
  925. *       visible
  926. *
  927. *****************************************************************************/
  928.  
  929. static void FreeCachedItem (Nlm_DocDataPtr ddatptr, Int2 item,
  930.                             Int2Ptr lowest, Int2Ptr highest)
  931.  
  932. {
  933.   ItemPtr  itemPtr;
  934.  
  935.   if (ddatptr != NULL) {
  936.     itemPtr = GetItemPtr (ddatptr, item);
  937.     if (itemPtr != NULL) {
  938.       itemPtr->text = (CharPtr) MemFree (itemPtr->text);
  939.       itemPtr->notCached = TRUE;
  940.       if (ddatptr->isvirtual && ddatptr->numItems > 0) {
  941.         itemPtr->numRows = 30000 / ddatptr->numItems;
  942.         CollectRange (item, lowest, highest);
  943.       }
  944.     }
  945.   }
  946. }
  947.  
  948. /*****************************************************************************
  949. *
  950. *   VisLinesAbove (ddatptr, r, item, line, lowest, highest)
  951. *       Returns the number of lines visible on the screen if the given line
  952. *       in the given item is the last line visible
  953. *
  954. *****************************************************************************/
  955.  
  956. static Int2 VisLinesAbove (Nlm_DocDataPtr ddatptr, RectPtr r, Int2 item,
  957.                            Int2 line, Int2Ptr lowest, Int2Ptr highest)
  958.  
  959. {
  960.   ItemPtr  itemPtr;
  961.   Int2     pixels;
  962.   Int2     vis;
  963.  
  964.   vis = 0;
  965.   if (ddatptr != NULL && r != NULL && item < ddatptr->numItems) {
  966.     pixels = r->bottom - r->top;
  967.     while (pixels > 0 && item >= 0) {
  968.       itemPtr = GetItemPtr (ddatptr, item);
  969.       if (itemPtr != NULL) {
  970.         CollectRange (item, lowest, highest);
  971.         CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
  972.         if (line < 0) {
  973.           line = itemPtr->numRows - 1;
  974.         }
  975.         while (pixels > 0 && line >= 0 && line < itemPtr->numRows) {
  976.           pixels -= itemPtr->lineHeight;
  977.           if (pixels >= 0) {
  978.             vis++;
  979.           }
  980.           line--;
  981.         }
  982.         pixels -= itemPtr->leadHeight;
  983.       }
  984.       item--;
  985.     }
  986.   }
  987.   return vis;
  988. }
  989.  
  990. /*****************************************************************************
  991. *
  992. *   VisLinesBelow (ddatptr, r, item, line, lowest, highest)
  993. *       Returns the number of lines visible on the screen if the given line
  994. *       in the given item is the first line visible
  995. *
  996. *****************************************************************************/
  997.  
  998. static Int2 VisLinesBelow (Nlm_DocDataPtr ddatptr, RectPtr r, Int2 item,
  999.                            Int2 line, Int2Ptr lowest, Int2Ptr highest)
  1000.  
  1001. {
  1002.   ItemPtr  itemPtr;
  1003.   Int2     pixels;
  1004.   Int2     vis;
  1005.  
  1006.   vis = 0;
  1007.   if (ddatptr != NULL && r != NULL && item < ddatptr->numItems && item >= 0) {
  1008.     pixels = r->bottom - r->top;
  1009.     while (pixels > 0 && item < ddatptr->numItems) {
  1010.       itemPtr = GetItemPtr (ddatptr, item);
  1011.       if (itemPtr != NULL) {
  1012.         CollectRange (item, lowest, highest);
  1013.         CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
  1014.         if (line  < 0) {
  1015.           line = 0;
  1016.           pixels -= itemPtr->leadHeight;
  1017.         }
  1018.         while (pixels > 0 && line >= 0 && line < itemPtr->numRows) {
  1019.           pixels -= itemPtr->lineHeight;
  1020.           if (pixels >= 0) {
  1021.             vis++;
  1022.           }
  1023.           line++;
  1024.         }
  1025.         line = -1;
  1026.       }
  1027.       item++;
  1028.     }
  1029.   }
  1030.   return vis;
  1031. }
  1032.  
  1033. /*****************************************************************************
  1034. *
  1035. *   PixelsBetween (ddatptr, r, firstLine, lastLine, lowest, highest)
  1036. *       Returns the number of pixels between two lines
  1037. *
  1038. *****************************************************************************/
  1039.  
  1040. static Int2 PixelsBetween (Nlm_DocDataPtr ddatptr, RectPtr r, Int2 firstLine,
  1041.                            Int2 lastLine, Int2Ptr lowest, Int2Ptr highest)
  1042.  
  1043. {
  1044.   Int2     count;
  1045.   Int2     item;
  1046.   ItemPtr  itemPtr;
  1047.   Int2     line;
  1048.   Int2     numLines;
  1049.   Int2     onItem;
  1050.   Int2     pixels;
  1051.  
  1052.   pixels = 0;
  1053.   if (ddatptr != NULL && r != NULL) {
  1054.     count = ABS (lastLine - firstLine);
  1055.     item = GetItemNum (ddatptr, MIN (firstLine, lastLine));
  1056.     itemPtr = GetItemPtr (ddatptr, item);
  1057.     onItem = item;
  1058.     if (itemPtr != NULL && item >= 0) {
  1059.       CollectRange (item, lowest, highest);
  1060.       CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
  1061.       line = MIN (firstLine, lastLine) - itemPtr->startsAt;
  1062.       while (count > 0 && item < ddatptr->numItems) {
  1063.         if (item != onItem) {
  1064.           itemPtr = GetItemPtr (ddatptr, item);
  1065.           onItem = item;
  1066.         }
  1067.         if (itemPtr != NULL) {
  1068.           CollectRange (item, lowest, highest);
  1069.           CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
  1070.           numLines = itemPtr->numRows;
  1071.           while (count > 0 && line >= 0 && line < numLines) {
  1072.             pixels += itemPtr->lineHeight;
  1073.             line++;
  1074.             count--;
  1075.           }
  1076.         }
  1077.         item++;
  1078.         if (line >= numLines) {
  1079.           itemPtr = GetItemPtr (ddatptr, item);
  1080.           onItem = item;
  1081.           if (itemPtr != NULL) {
  1082.             CollectRange (item, lowest, highest);
  1083.             CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
  1084.             pixels += itemPtr->leadHeight;
  1085.           }
  1086.         }
  1087.         line = 0;
  1088.       }
  1089.       if (lastLine < firstLine) {
  1090.         pixels = -pixels;
  1091.       }
  1092.     }
  1093.   }
  1094.   return pixels;
  1095. }
  1096.  
  1097. /*****************************************************************************
  1098. *
  1099. *   DrawTableItem (d, itemPtr, r, item, frst, grayProc,
  1100.                    invertProc, colorProc, force, tabCount)
  1101. *       Draws a given item on the screen, suppressing partial lines
  1102. *
  1103. *****************************************************************************/
  1104.  
  1105. static Int2 DrawTableItem (DoC d, ItemPtr itemPtr, RectPtr r, Int2 item,
  1106.                           Int2 frst, DocShadeProc grayProc,
  1107.                           DocShadeProc invertProc, DocShadeProc colorProc,
  1108.                           Boolean force, Int2 tabCount)
  1109.  
  1110. {
  1111.   Char     ch;
  1112.   Int2     col;
  1113.   Boolean  color;
  1114.   ColXPtr  colFmt;
  1115.   FonT     curFont;
  1116.   Uint4    currentColor;
  1117.   RecT     drw;
  1118.   FonT     fnt;
  1119.   Boolean  gray;
  1120.   Int2     insetLeft;
  1121.   Int2     insetRight;
  1122.   Boolean  invert;
  1123.   Char     just;
  1124.   Int2     lineHeight;
  1125.   Int2     num;
  1126.   CharPtr  ptr;
  1127.   RecT     rct;
  1128.   Int2     row;
  1129.   Int2     rsult;
  1130.   CharPtr  text;
  1131.  
  1132.   rsult = 0;
  1133.   if (d != NULL && itemPtr != NULL && r != NULL) {
  1134.     text = itemPtr->text;
  1135.     colFmt = itemPtr->colFmt;
  1136.     if (text != NULL && *text != '\0' && colFmt != NULL) {
  1137.       fnt = itemPtr->font;
  1138.       if (fnt != NULL) {
  1139.         SelectFont (fnt);
  1140.         curFont = fnt;
  1141.       } else {
  1142.         SelectFont (systemFont);
  1143.         curFont = systemFont;
  1144.       }
  1145.       lineHeight = itemPtr->lineHeight;
  1146.       rct.top = r->top;
  1147.       rct.bottom = rct.top;
  1148.       row = 0;
  1149.       col = 0;
  1150.       ptr = text;
  1151.       ch = *ptr;
  1152.       if (colorProc != NULL && (! force)) {
  1153.         currentColor = GetColor ();
  1154.       }
  1155.       while (ch != '\0') {
  1156.         if (ch == '\n') {
  1157.           rct.top = r->top + (row - frst) * lineHeight;
  1158.           rct.bottom = rct.top + lineHeight;
  1159.           InvertMode ();
  1160.           for (col = 0; col < itemPtr->numCols; col++) {
  1161.             rct.left = colFmt [col].position;
  1162.             rct.right = rct.left + colFmt [col].pixWidth;
  1163.             if (colFmt [col].bar) {
  1164.               MoveTo (rct.left, rct.top);
  1165.               LineTo (rct.left, rct.bottom - 1);
  1166.             }
  1167.             if (colFmt [col].underline) {
  1168.               MoveTo (rct.left, rct.bottom - 1);
  1169.               LineTo (rct.right, rct.bottom - 1);
  1170.             }
  1171.           }
  1172.           CopyMode ();
  1173.           col = 0;
  1174.           row++;
  1175.           ptr++;
  1176.         } else if (ch == '\t' && (! (itemPtr->tabStops))) {
  1177.           col++;
  1178.           ptr++;
  1179.         } else  {
  1180.           num = 0;
  1181.           while (ch != '\0' && (ch != '\t' || itemPtr->tabStops) && ch != '\n') {
  1182.             num++;
  1183.             ch = ptr [num];
  1184.           }
  1185.           if (row >= frst && col < itemPtr->numCols) {
  1186.             rct.top = r->top + (row - frst) * lineHeight;
  1187.             rct.bottom = rct.top + lineHeight;
  1188.             rct.left = colFmt [col].position;
  1189.             rct.right = rct.left + colFmt [col].pixWidth;
  1190.             LoadRect (&drw, MAX (rct.left, r->left), rct.top,
  1191.                       MIN (rct.right, r->right), rct.bottom);
  1192.             if (RectInRect (&drw, r) &&
  1193.                 (force || updateRgn == NULL || RectInRgn (&rct, updateRgn))) {
  1194.               just = justToChar [colFmt [col].just];
  1195.               if (just == 'c') {
  1196.                 insetLeft = colFmt [col].pixInset;
  1197.                 insetRight = colFmt [col].pixInset;
  1198.               } else if (just == 'l') {
  1199.                 insetLeft = colFmt [col].pixInset;
  1200.                 insetRight = 0;
  1201.               } else if (just == 'r') {
  1202.                 insetLeft = 0;
  1203.                 insetRight = colFmt [col].pixInset;
  1204.               } else {
  1205.                 insetLeft = 0;
  1206.                 insetRight = 0;
  1207.               }
  1208.               fnt = colFmt [col].font;
  1209.               if (fnt != NULL) {
  1210.                 if (fnt != curFont) {
  1211.                   SelectFont (fnt);
  1212.                   curFont = fnt;
  1213.                 }
  1214.               } else {
  1215.                 fnt = itemPtr->font;
  1216.                 if (fnt != NULL) {
  1217.                   if (fnt != curFont) {
  1218.                     SelectFont (fnt);
  1219.                     curFont = fnt;
  1220.                   }
  1221.                 }
  1222.               }
  1223.               if (colorProc != NULL && (! force)) {
  1224.                 color = colorProc (d, item + 1, row + 1, col + 1);
  1225.                 if (! color) {
  1226.                   SetColor (currentColor);
  1227.                 }
  1228.               } else {
  1229.                 color = FALSE;
  1230.               }
  1231.               if (invertProc != NULL && (! force)) {
  1232.                 invert = invertProc (d, item + 1, row + 1, col + 1);
  1233.               } else {
  1234.                 invert = FALSE;
  1235.               }
  1236.               if (grayProc != NULL && (! force)) {
  1237.                 gray = grayProc (d, item + 1, row + 1, col + 1);
  1238.               } else {
  1239.                 gray = FALSE;
  1240.               }
  1241.               if (invert) {
  1242.                 InvertColors ();
  1243.                 EraseRect (&rct);
  1244.               }
  1245.               rct.left += insetLeft;
  1246.               rct.right -= insetRight;
  1247.               drw = rct;
  1248.               if (num > 0) {
  1249.                 while (num > 0 && *ptr == '\t') {
  1250.                   num--;
  1251.                   ptr++;
  1252.                   drw.left += CharWidth (' ') * tabCount;
  1253.                 }
  1254.                 DrawText (&drw, ptr, num, just, gray);
  1255.               }
  1256.               if (invert) {
  1257.                 InvertColors ();
  1258.               }
  1259.               if (colorProc != NULL && (! force)) {
  1260.                 SetColor (currentColor);
  1261.               }
  1262.               rct.left -= insetLeft;
  1263.               rct.right += insetRight;
  1264.             }
  1265.           }
  1266.           ptr += num;
  1267.         }
  1268.         ch = *ptr;
  1269.       }
  1270.       rct.top = rct.bottom;
  1271.       rsult = rct.top - r->top;
  1272.     }
  1273.     SelectFont (systemFont);
  1274.   }
  1275.   return rsult;
  1276. }
  1277.  
  1278. /*****************************************************************************
  1279. *
  1280. *   DrawDocument (d)
  1281. *       Panel callback that traverses the item list and draws visible items
  1282. *       Clipping is to the intersection of the updateRgn (the portion of the
  1283. *       panel exposed) and the inset area of the document, leaving a four-
  1284. *       pixel margin
  1285. *
  1286. *****************************************************************************/
  1287.  
  1288. static void DrawDocument (PaneL d)
  1289.  
  1290. {
  1291.   DocData  ddata;
  1292.   RegioN   dst;
  1293.   Int2     firstLine;
  1294.   Int2     highest;
  1295.   Int2     item;
  1296.   ItemPtr  itemPtr;
  1297.   Int2     lowest;
  1298.   Int2     off;
  1299.   Int2     pixels;
  1300.   RecT     r;
  1301.   RecT     rct;
  1302.   BaR      sb;
  1303.   RegioN   src;
  1304.  
  1305.   GetPanelExtra (d, &ddata);
  1306.   if (ddata.numItems > 0) {
  1307.     ObjectRect (d, &r);
  1308.     InsetRect (&r, 4, 4);
  1309.     sb = GetSlateVScrollBar ((SlatE) d);
  1310.     if (sb != NULL) {
  1311.       src = CreateRgn ();
  1312.       dst = CreateRgn ();
  1313.       LoadRectRgn (src, r.left, r.top, r.right, r.bottom);
  1314.       SectRgn (src, updateRgn, dst);
  1315.       ClipRgn (dst);
  1316.       DestroyRgn (src);
  1317.       DestroyRgn (dst);
  1318.       off = GetValue (sb);
  1319.       pixels = 0;
  1320.       lowest = INT2_MAX;
  1321.       highest = INT2_MIN;
  1322.       item = GetItemNum (&ddata, off);
  1323.       itemPtr = GetItemPtr (&ddata, item);
  1324.       if (itemPtr != NULL) {
  1325.         firstLine = off - itemPtr->startsAt;
  1326.         do {
  1327.           if (itemPtr != NULL) {
  1328.             if (itemPtr->neverCached) {
  1329.               CollectRange (item, &lowest, &highest);
  1330.             }
  1331.             CacheAndFormat (&ddata, item + 1, itemPtr, &r, ddata.tabCount);
  1332.             SetTablePixFormat (itemPtr->colFmt, r.left, itemPtr->numCols);
  1333.             if (pixels != 0) {
  1334.               r.top += itemPtr->leadHeight;
  1335.             }
  1336.             rct = r;
  1337.             rct.bottom = rct.top + itemPtr->lineHeight * (itemPtr->numRows - firstLine);
  1338.             if (updateRgn == NULL || RectInRgn (&rct, updateRgn)) {
  1339.               pixels = DrawTableItem ((DoC) d, itemPtr, &r, item, firstLine,
  1340.                                       ddata.gray, ddata.invert, ddata.color,
  1341.                                       FALSE, ddata.tabCount);
  1342.               if (ddata.draw != NULL) {
  1343.                 ddata.draw ((DoC) d, &r, item + 1, firstLine);
  1344.                 ResetDrawingTools ();
  1345.               }
  1346.             } else {
  1347.               pixels = rct.bottom - rct.top;
  1348.             }
  1349.             r.top += pixels;
  1350.           }
  1351.           item++;
  1352.           firstLine = 0;
  1353.           itemPtr = GetItemPtr (&ddata, item);
  1354.         } while (r.top < r.bottom && item < ddata.numItems);
  1355.         if (lowest < INT2_MAX) {
  1356.           ddata.numLines = UpdateLineStarts (&ddata, lowest);
  1357.           SetPanelExtra (d, &ddata);
  1358.         }
  1359.       }
  1360.       ResetClip ();
  1361.     }
  1362.   }
  1363.   SelectFont (systemFont);
  1364. }
  1365.  
  1366. /*****************************************************************************
  1367. *
  1368. *   DocumentScrlProc (sb, s, newval, oldval)
  1369. *       Scroll bar callback that takes suppressed partial lines into account
  1370. *
  1371. *****************************************************************************/
  1372.  
  1373. static void DocumentScrlProc (BaR sb, SlatE s, Int2 newval, Int2 oldval)
  1374.  
  1375. {
  1376.   Int2     barmax;
  1377.   Int2     barval;
  1378.   DocData  ddata;
  1379.   Int2     firstShown;
  1380.   Boolean  goToEnd;
  1381.   Int2     height;
  1382.   Int2     highest;
  1383.   Int2     highFree;
  1384.   Int2     item;
  1385.   ItemPtr  itemPtr;
  1386.   Int2     last;
  1387.   Int2     limit;
  1388.   Int2     line;
  1389.   Int2     lineInto;
  1390.   Int2     lowest;
  1391.   Int2     lowFree;
  1392.   Int2     min;
  1393.   Int2     pixels;
  1394.   Int2     pgDn;
  1395.   Int2     pgUp;
  1396.   RecT     r;
  1397.   Int2     vis;
  1398.  
  1399.   if (s != NULL && oldval != newval) {
  1400.     if (Visible (s) && AllParentsVisible (s)) {
  1401.       GetPanelExtra ((PaneL) s, &ddata);
  1402.       ObjectRect (s, &r);
  1403.       InsetRect (&r, 4, 4);
  1404.       height = r.bottom - r.top;
  1405.       item = GetItemNum (&ddata, newval);
  1406.       line = newval - GetStartsAt (&ddata, item);
  1407.       firstShown = item;
  1408.       lineInto = line;
  1409.       lowest = INT2_MAX;
  1410.       highest = INT2_MIN;
  1411.       pgUp = VisLinesAbove (&ddata, &r, item, line, &lowest, &highest) - 1;
  1412.       pgDn = VisLinesBelow (&ddata, &r, item, line, &lowest, &highest) - 1;
  1413.       if (pgDn < 1) {
  1414.         pgDn = 1;
  1415.       }
  1416.       if (pgUp < 1) {
  1417.         pgUp = 1;
  1418.       }
  1419.       if (lowest < INT2_MAX) {
  1420.         ddata.numLines = UpdateLineStarts (&ddata, lowest);
  1421.         SetPanelExtra ((PaneL) s, &ddata);
  1422.       }
  1423.       Select (s);
  1424.       if ((newval > oldval && newval - pgUp <= oldval) ||
  1425.           (newval < oldval && newval + pgDn >= oldval)) {
  1426.         pixels = PixelsBetween (&ddata, &r, newval, oldval, NULL, NULL);
  1427.         if (ABS (pixels) < height) {
  1428.           min = MIN (oldval, newval);
  1429.           item = GetItemNum (&ddata, min);
  1430.           line = min - GetStartsAt (&ddata, item);
  1431.           vis = VisLinesBelow (&ddata, &r, item, line, NULL, NULL);
  1432.           last = min + vis - 1;
  1433.           limit = PixelsBetween (&ddata, &r, newval, last, NULL, NULL);
  1434.           item = GetItemNum (&ddata, last);
  1435.           line = last - GetStartsAt (&ddata, item);
  1436.           limit += GetLineHeight (&ddata, item);
  1437.           ScrollRect (&r, 0, pixels);
  1438.           r.top += limit;
  1439.           InsetRect (&r, -1, -1);
  1440.           InvalRect (&r);
  1441.         } else {
  1442.           InsetRect (&r, -1, -1);
  1443.           InvalRect (&r);
  1444.         }
  1445.       } else {
  1446.         InsetRect (&r, -1, -1);
  1447.         InvalRect (&r);
  1448.       }
  1449.       lowFree = INT2_MAX;
  1450.       highFree = INT2_MIN;
  1451.       for (item = 0; item < lowest; item++) {
  1452.         FreeCachedItem (&ddata, item, &lowFree, &highFree);
  1453.       }
  1454.       for (item = highest + 1; item < ddata.numItems; item++) {
  1455.         FreeCachedItem (&ddata, item, &lowFree, &highFree);
  1456.       }
  1457.       if (lowFree < INT2_MAX) {
  1458.         ddata.numLines = UpdateLineStarts (&ddata, lowFree);
  1459.         SetPanelExtra ((PaneL) s, &ddata);
  1460.       }
  1461.       barmax = 0;
  1462.       goToEnd = (Boolean) (newval == ddata.barmax);
  1463.       if (ddata.numLines > 0 && ddata.numItems > 0) {
  1464.         itemPtr = GetItemPtr (&ddata, ddata.numItems - 1);
  1465.         if (itemPtr != NULL) {
  1466.           ObjectRect (s, &r);
  1467.           InsetRect (&r, 4, 4);
  1468.           lowest = INT2_MAX;
  1469.           highest = INT2_MIN;
  1470.           vis = VisLinesAbove (&ddata, &r, ddata.numItems - 1,
  1471.                                itemPtr->numRows - 1, &lowest, &highest);
  1472.           if (lowest < INT2_MAX) {
  1473.             ddata.numLines = UpdateLineStarts (&ddata, lowest);
  1474.             SetPanelExtra ((PaneL) s, &ddata);
  1475.           }
  1476.           barmax = ddata.numLines - vis;
  1477.         }
  1478.       }
  1479.       barval = GetStartsAt (&ddata, firstShown) + lineInto;
  1480.       if (goToEnd) {
  1481.         barval = barmax;
  1482.       }
  1483.       if (barval > ddata.barmax) {
  1484.         CorrectBarMax (sb, barmax);
  1485.         CorrectBarValue (sb, barval);
  1486.       } else {
  1487.         CorrectBarValue (sb, barval);
  1488.         CorrectBarMax (sb, barmax);
  1489.       }
  1490.       CorrectBarPage (sb, pgUp, pgDn);
  1491.       ddata.barmax = barmax;
  1492.       SetPanelExtra ((PaneL) s, &ddata);
  1493.       Update ();
  1494.       if (ddata.pan != NULL) {
  1495.         Select (s);
  1496.         ddata.pan ((DoC) s);
  1497.       }
  1498.     }
  1499.   }
  1500. }
  1501.  
  1502. /*****************************************************************************
  1503. *
  1504. *   CreateItemPtr (d, item)
  1505. *       Adds an item slot to the item list
  1506. *
  1507. *****************************************************************************/
  1508.  
  1509. static ItemPtr CreateItemPtr (DoC d, Int2 item)
  1510.  
  1511. {
  1512.   DocData    ddata;
  1513.   Int2       index;
  1514.   Int2       list;
  1515.   ItemPtr    itemPtr;
  1516.   Nlm_ListPtr    listPtr;
  1517.   MasterPtr  masterPtr;
  1518.  
  1519.   itemPtr = NULL;
  1520.   if (d != NULL && item < 32767) {
  1521.     GetPanelExtra ((PaneL) d, &ddata);
  1522.     list = (item / LISTSIZE);
  1523.     if (ddata.master == NULL) {
  1524.       ddata.master = (MasterPtr) MemNew (sizeof (MasterData));
  1525.       SetPanelExtra ((PaneL) d, &ddata);
  1526.     }
  1527.     if (list < MAXLISTS && ddata.master != NULL) {
  1528.       masterPtr = ddata.master;
  1529.       listPtr = masterPtr->list [list];
  1530.       if (listPtr == NULL) {
  1531.         masterPtr->list [list] = (Nlm_ListPtr)MemNew (sizeof (ListData));
  1532.         listPtr = masterPtr->list [list];
  1533.       }
  1534.       if (listPtr != NULL) {
  1535.         index = (item % LISTSIZE);
  1536.         itemPtr = &(listPtr->items [index]);
  1537.       }
  1538.     }
  1539.   }
  1540.   return itemPtr;
  1541. }
  1542.  
  1543. /*****************************************************************************
  1544. *
  1545. *   GetFontHeight (font)
  1546. *       Returns the pixel height of a font, caching for quicker access
  1547. *
  1548. *****************************************************************************/
  1549.  
  1550. static Int2 GetFontHeight (FonT font)
  1551.  
  1552. {
  1553.   Int2  height;
  1554.   Int2  i;
  1555.  
  1556.   height = 0;
  1557.   i = 0;
  1558.   while (i < MAXFONTS && fontHeights [i].font != font && fontHeights [i].font != NULL) {
  1559.     i++;
  1560.   }
  1561.   if (fontHeights [i].font == font) {
  1562.     height = fontHeights [i].height;
  1563.   } else {
  1564.     SelectFont (font);
  1565.     height = LineHeight ();
  1566.     if (i < MAXFONTS) {
  1567.       fontHeights [i].font = font;
  1568.       fontHeights [i].height = height;
  1569.     }
  1570.   }
  1571.   return height;
  1572. }
  1573.  
  1574. /*****************************************************************************
  1575. *
  1576. *   UpdateItemHeights (itemPtr)
  1577. *       Returns the maximum height of all fonts used in an item
  1578. *
  1579. *****************************************************************************/
  1580.  
  1581. static void UpdateItemHeights (ItemPtr itemPtr)
  1582.  
  1583. {
  1584.   ColXPtr  colFmt;
  1585.   FonT     fnt;
  1586.   Int2     i;
  1587.   Int2     linhgt;
  1588.   Int2     maxhgt;
  1589.  
  1590.   if (itemPtr != NULL) {
  1591.     colFmt = itemPtr->colFmt;
  1592.     maxhgt = 0;
  1593.     if (colFmt != NULL) {
  1594.       i = itemPtr->numCols;
  1595.       while (i > 0) {
  1596.         i--;
  1597.         fnt = colFmt [i].font;
  1598.         if (fnt != NULL) {
  1599.           linhgt = GetFontHeight (fnt);
  1600.           if (linhgt > maxhgt) {
  1601.             maxhgt = linhgt;
  1602.           }
  1603.         }
  1604.       }
  1605.     }
  1606.     fnt = itemPtr->font;
  1607.     if (fnt != NULL) {
  1608.       linhgt = GetFontHeight (fnt);
  1609.       if (linhgt > maxhgt) {
  1610.         maxhgt = linhgt;
  1611.       }
  1612.     }
  1613.     if (maxhgt == 0) {
  1614.       maxhgt = stdLineHeight;
  1615.     }
  1616.     itemPtr->lineHeight = MAX (maxhgt, itemPtr->minHeight);
  1617.     if (itemPtr->openSpace) {
  1618.       itemPtr->leadHeight = maxhgt;
  1619.     } else {
  1620.       itemPtr->leadHeight = 0;
  1621.     }
  1622.   }
  1623. }
  1624.  
  1625. /*****************************************************************************
  1626. *
  1627. *   SetDocAutoAdjust (d, autoAdjust)
  1628. *       Sets the document automatic scroll adjust parameter
  1629. *
  1630. *****************************************************************************/
  1631.  
  1632. extern void SetDocAutoAdjust (DoC d, Boolean autoAdjust)
  1633.  
  1634. {
  1635.   DocData  ddata;
  1636.  
  1637.   if (d != NULL) {
  1638.     GetPanelExtra ((PaneL) d, &ddata);
  1639.     ddata.autoAdjust = autoAdjust;
  1640.     SetPanelExtra ((PaneL) d, &ddata);
  1641.   }
  1642. }
  1643.  
  1644. /*****************************************************************************
  1645. *
  1646. *   SetDocVirtual (d, isvirtual)
  1647. *       Sets the document isvirtual scroll parameter
  1648. *
  1649. *****************************************************************************/
  1650.  
  1651. /* dgg -- "isvirtual" name conflicts w/ c++ syntax word -> isvirtual */
  1652.  
  1653. extern void SetDocVirtual (DoC d, Boolean isvirtual)
  1654.  
  1655. {
  1656.   DocData  ddata;
  1657.  
  1658.   if (d != NULL) {
  1659.     GetPanelExtra ((PaneL) d, &ddata);
  1660.     ddata.isvirtual = isvirtual;
  1661.     SetPanelExtra ((PaneL) d, &ddata);
  1662.   }
  1663. }
  1664.  
  1665. /* dgg here -- want to make use of tab settings other than from FancyFile call */
  1666.  
  1667. /*****************************************************************************
  1668. *
  1669. *   Nlm_SetDocTabstops (d, tabStops)
  1670. *       Sets the document tap stop interval
  1671. *
  1672. *****************************************************************************/
  1673.  
  1674. extern void Nlm_SetDocTabstops (DoC d, Int2 tabStops)
  1675. {
  1676.   DocData  ddata;
  1677.  
  1678.   if (d != NULL) {
  1679.     GetPanelExtra ((PaneL) d, &ddata);
  1680.     ddata.tabCount = tabStops;
  1681.     SetPanelExtra ((PaneL) d, &ddata);
  1682.   }
  1683. }
  1684.  
  1685. /*****************************************************************************
  1686. *
  1687. *   AdjustDocScroll (d)
  1688. *       Calculates an estimate for the scroll bar maximum
  1689. *
  1690. *****************************************************************************/
  1691.  
  1692. extern void AdjustDocScroll (DoC d)
  1693.  
  1694. {
  1695.   Int2     barmax;
  1696.   Int2     barval;
  1697.   DocData  ddata;
  1698.   Int2     firstShown;
  1699.   Int2     highest;
  1700.   Int2     item;
  1701.   ItemPtr  itemPtr;
  1702.   Int2     line;
  1703.   Int2     lineInto;
  1704.   Int2     lowest;
  1705.   Int2     pgDn;
  1706.   Int2     pgUp;
  1707.   RecT     r;
  1708.   BaR      sb;
  1709.   Int2     vis;
  1710.  
  1711.   if (d != NULL) {
  1712.     GetPanelExtra ((PaneL) d, &ddata);
  1713.     SelectFont (systemFont);
  1714.     sb = GetSlateVScrollBar ((SlatE) d);
  1715.     if (sb != NULL) {
  1716.       if (ddata.numLines > 0 && ddata.numItems > 0) {
  1717.         ObjectRect (d, &r);
  1718.         InsetRect (&r, 4, 4);
  1719.         barval = GetValue (sb);
  1720.         item = GetItemNum (&ddata, barval);
  1721.         line = barval - GetStartsAt (&ddata, item);
  1722.         firstShown = item;
  1723.         lineInto = line;
  1724.         lowest = INT2_MAX;
  1725.         highest = INT2_MIN;
  1726.         itemPtr = GetItemPtr (&ddata, ddata.numItems - 1);
  1727.         if (itemPtr != NULL) {
  1728.           vis = VisLinesAbove (&ddata, &r, ddata.numItems - 1,
  1729.                                itemPtr->numRows - 1, &lowest, &highest);
  1730.         }
  1731.         pgUp = VisLinesAbove (&ddata, &r, item, line, &lowest, &highest) - 1;
  1732.         pgDn = VisLinesBelow (&ddata, &r, item, line, &lowest, &highest) - 1;
  1733.         if (pgDn < 1) {
  1734.           pgDn = 1;
  1735.         }
  1736.         if (pgUp < 1) {
  1737.           pgUp = 1;
  1738.         }
  1739.         if (lowest < INT2_MAX) {
  1740.           ddata.numLines = UpdateLineStarts (&ddata, lowest);
  1741.           SetPanelExtra ((PaneL) d, &ddata);
  1742.         }
  1743.         itemPtr = GetItemPtr (&ddata, ddata.numItems - 1);
  1744.         if (itemPtr != NULL) {
  1745.           barmax = 0;
  1746.           ObjectRect (d, &r);
  1747.           InsetRect (&r, 4, 4);
  1748.           lowest = INT2_MAX;
  1749.           highest = INT2_MIN;
  1750.           vis = VisLinesAbove (&ddata, &r, ddata.numItems - 1,
  1751.                                itemPtr->numRows - 1, &lowest, &highest);
  1752.           if (lowest < INT2_MAX) {
  1753.             ddata.numLines = UpdateLineStarts (&ddata, lowest);
  1754.             SetPanelExtra ((PaneL) d, &ddata);
  1755.           }
  1756.           barmax = ddata.numLines - vis;
  1757.           barval = GetStartsAt (&ddata, firstShown) + lineInto;
  1758.           CorrectBarPage (sb, pgUp, pgDn);
  1759.           if (barval > ddata.barmax) {
  1760.             CorrectBarMax (sb, barmax);
  1761.             CorrectBarValue (sb, barval);
  1762.           } else {
  1763.             CorrectBarValue (sb, barval);
  1764.             CorrectBarMax (sb, barmax);
  1765.           }
  1766.           ddata.barmax = barmax;
  1767.           SetPanelExtra ((PaneL) d, &ddata);
  1768.         }
  1769.       } else {
  1770.         Reset (sb);
  1771.       }
  1772.     }
  1773.   }
  1774. }
  1775.  
  1776. /*
  1777. extern void AdjustDocScroll (DoC d)
  1778.  
  1779. {
  1780.   Int2     barmax;
  1781.   DocData  ddata;
  1782.   Int2     firstLine;
  1783.   Int2     highest;
  1784.   Int2     item;
  1785.   ItemPtr  itemPtr;
  1786.   Int2     line;
  1787.   Int2     lowest;
  1788.   Int2     pgDn;
  1789.   RecT     r;
  1790.   BaR      sb;
  1791.   Int2     vis;
  1792.  
  1793.   if (d != NULL) {
  1794.     GetPanelExtra ((PaneL) d, &ddata);
  1795.     SelectFont (systemFont);
  1796.     sb = GetSlateVScrollBar ((SlatE) d);
  1797.     if (sb != NULL) {
  1798.       barmax = 0;
  1799.       ObjectRect (d, &r);
  1800.       InsetRect (&r, 4, 4);
  1801.       if (ddata.numLines > 0 && ddata.numItems > 0) {
  1802.         lowest = INT2_MAX;
  1803.         highest = INT2_MIN;
  1804.         pgDn = VisLinesBelow (&ddata, &r, 0, 0, &lowest, &highest) - 1;
  1805.         if (lowest < INT2_MAX) {
  1806.           ddata.numLines = UpdateLineStarts (&ddata, lowest);
  1807.           SetPanelExtra ((PaneL) d, &ddata);
  1808.         }
  1809.         if (pgDn >= 0 && pgDn < ddata.numLines) {
  1810.           item = GetItemNum (&ddata, pgDn);
  1811.           itemPtr = GetItemPtr (&ddata, item);
  1812.           if (itemPtr != NULL) {
  1813.             firstLine = pgDn - itemPtr->startsAt;
  1814.             lowest = INT2_MAX;
  1815.             highest = INT2_MIN;
  1816.             vis = VisLinesBelow (&ddata, &r, item, firstLine, &lowest, &highest) - 1;
  1817.             if (lowest < INT2_MAX) {
  1818.               ddata.numLines = UpdateLineStarts (&ddata, lowest);
  1819.             }
  1820.             if (vis >= 0 && pgDn + vis < ddata.numLines) {
  1821.               item = GetItemNum (&ddata, pgDn + vis);
  1822.               line = GetNumRows (&ddata, item) - 1;
  1823.               vis = VisLinesAbove (&ddata, &r, item, line, NULL, NULL);
  1824.             }
  1825.             barmax = ddata.numLines - vis;
  1826.             SetRange (sb, 1, pgDn, barmax);
  1827.             ddata.barmax = barmax;
  1828.             SetPanelExtra ((PaneL) d, &ddata);
  1829.           }
  1830.         }
  1831.       }
  1832.     }
  1833.   }
  1834. }
  1835. */
  1836.  
  1837. /*****************************************************************************
  1838. *
  1839. *   defaultTable
  1840. *       Column format used if the colFmt parameter is NULL
  1841. *
  1842. *****************************************************************************/
  1843.  
  1844. static ColData defaultTable = {0, 0, 0, 0, NULLFONT, 'l',
  1845.                                TRUE, FALSE, FALSE, FALSE, TRUE};
  1846.  
  1847. /*****************************************************************************
  1848. *
  1849. *   CacheColFmt (d, colFmt)
  1850. *       Caches the colFmt format structure
  1851. *
  1852. *****************************************************************************/
  1853.  
  1854. static ColXPtr CacheColFmt (DoC d, ColPtr colFmt)
  1855.  
  1856. {
  1857.   DocData     ddata;
  1858.   Boolean     found;
  1859.   Boolean     goOn;
  1860.   Int2        i;
  1861.   Int2        numCols;
  1862.   ColXPtr     rsult;
  1863.   ColXPtr     thisCol;
  1864.   ValNodePtr  vnp;
  1865.  
  1866.   rsult = NULL;
  1867.   if (d != NULL && colFmt != NULL) {
  1868.     i = 0;
  1869.     while (! colFmt [i].last) {
  1870.       i++;
  1871.     }
  1872.     i++;
  1873.     numCols = i;
  1874.     rsult = (ColXPtr) MemNew (numCols * sizeof (ColXData));
  1875.     if (rsult != NULL) {
  1876.       for (i = 0; i < numCols; i++) {
  1877.         rsult [i].position = 0;
  1878.         rsult [i].pixWidth = colFmt [i].pixWidth;
  1879.         rsult [i].pixInset = colFmt [i].pixInset;
  1880.         rsult [i].charWidth = colFmt [i].charWidth;
  1881.         rsult [i].charInset = colFmt [i].charInset;
  1882.         if (colFmt [i].just == 'l') {
  1883.           rsult [i].just = JUST_LEFT;
  1884.         } else if (colFmt [i].just == 'c') {
  1885.           rsult [i].just = JUST_CENTER;
  1886.         } else if (colFmt [i].just == 'r') {
  1887.           rsult [i].just = JUST_RIGHT;
  1888.         } else {
  1889.           rsult [i].just = JUST_LEFT;
  1890.         }
  1891.         rsult [i].font = colFmt [i].font;
  1892.         rsult [i].zeroWidth = (Boolean) (colFmt [i].pixWidth == 0);
  1893.         if (rsult [i].zeroWidth) {
  1894.           rsult [i].charWidth = 0;
  1895.         }
  1896.         rsult [i].wrap = colFmt [i].wrap;
  1897.         rsult [i].bar = colFmt [i].bar;
  1898.         rsult [i].underline = colFmt [i].underline;
  1899.         rsult [i].left = colFmt [i].left;
  1900.         rsult [i].last = colFmt [i].last;
  1901.       }
  1902.       GetPanelExtra ((PaneL) d, &ddata);
  1903.       vnp = ddata.colFmts;
  1904.       goOn = TRUE;
  1905.       while (vnp != NULL && goOn) {
  1906.         thisCol = (ColXPtr) vnp->data.ptrvalue;
  1907.         if (thisCol != NULL) {
  1908.           i = 0;
  1909.           while (! thisCol [i].last) {
  1910.             i++;
  1911.           }
  1912.           i++;
  1913.           if (i == numCols) {
  1914.             found = TRUE;
  1915.             for (i = 0; i < numCols; i++) {
  1916.               if (thisCol [i].zeroWidth) {
  1917.                 thisCol [i].pixWidth = 0;
  1918.                 thisCol [i].charWidth = 0;
  1919.               }
  1920.               if (thisCol [i].font != rsult [i].font ||
  1921.                   thisCol [i].pixWidth != rsult [i].pixWidth ||
  1922.                   thisCol [i].pixInset != rsult [i].pixInset ||
  1923.                   thisCol [i].charWidth != rsult [i].charWidth ||
  1924.                   thisCol [i].charInset != rsult [i].charInset ||
  1925.                   thisCol [i].just != rsult [i].just ||
  1926.                   thisCol [i].zeroWidth != rsult [i].zeroWidth ||
  1927.                   thisCol [i].wrap != rsult [i].wrap ||
  1928.                   thisCol [i].bar != rsult [i].bar ||
  1929.                   thisCol [i].underline != rsult [i].underline ||
  1930.                   thisCol [i].left != rsult [i].left ||
  1931.                   thisCol [i].last != rsult [i].last) {
  1932.                 found = FALSE;
  1933.               }
  1934.             }
  1935.             if (found) {
  1936.               goOn = FALSE;
  1937.             }
  1938.           }
  1939.         }
  1940.         if (goOn) {
  1941.           vnp = vnp->next;
  1942.         }
  1943.       }
  1944.       if (goOn) {
  1945.         vnp = ValNodeNew (ddata.colFmts);
  1946.         if (vnp != NULL) {
  1947.           vnp->data.ptrvalue = (Pointer) rsult;
  1948.         }
  1949.         if (ddata.colFmts == NULL) {
  1950.           ddata.colFmts = vnp;
  1951.           SetPanelExtra ((PaneL) d, &ddata);
  1952.         }
  1953.       } else {
  1954.         MemFree (rsult);
  1955.         rsult = (ColXPtr) vnp->data.ptrvalue;
  1956.       }
  1957.     }
  1958.   }
  1959.   return rsult;
  1960. }
  1961.  
  1962. /*****************************************************************************
  1963. *
  1964. *   SetupItem (d, itemPtr, proc, data, docOwnsData,
  1965.                lines, parFmt, colFmt, font)
  1966. *       Processes user parameters into an item to append or insert into
  1967. *       the item list, or replace an item currently in the item list
  1968. *
  1969. *****************************************************************************/
  1970.  
  1971. static void SetupItem (DoC d, ItemPtr itemPtr, DocPrntProc proc, Pointer data,
  1972.                        Boolean docOwnsData, Int2 lines,
  1973.                        ParPtr parFmt, ColPtr colFmt, FonT font)
  1974.  
  1975. {
  1976.   Int2  i;
  1977.   RecT  r;
  1978.  
  1979.   if (d != NULL && itemPtr != NULL && proc != NULL) {
  1980.     ObjectRect (d, &r);
  1981.     InsetRect (&r, 4, 4);
  1982.     itemPtr->prtProc = proc;
  1983.     itemPtr->dataPtr = data;
  1984.     itemPtr->text = NULL;
  1985.     itemPtr->font = font;
  1986.     if (colFmt == NULL) {
  1987.       defaultTable.pixWidth = r.right - r.left;
  1988.       defaultTable.charWidth = 80;
  1989.       colFmt = &defaultTable;
  1990.     }
  1991.     i = 0;
  1992.     while (! colFmt [i].last) {
  1993.       i++;
  1994.     }
  1995.     i++;
  1996.     itemPtr->numCols = i;
  1997.     itemPtr->numRows = MAX (lines, 1);
  1998.     itemPtr->colFmt = CacheColFmt (d, colFmt);
  1999.     itemPtr->extra = NULL;
  2000.     itemPtr->startsAt = 0;
  2001.     if (parFmt != NULL) {
  2002.       itemPtr->openSpace = parFmt->openSpace;
  2003.       itemPtr->keepWithNext = parFmt->keepWithNext;
  2004.       itemPtr->keepTogether = parFmt->keepTogether;
  2005.       itemPtr->newPage = parFmt->newPage;
  2006.       itemPtr->tabStops = parFmt->tabStops;
  2007.       itemPtr->minLines = MAX (parFmt->minLines, (Int2) 1);
  2008.       itemPtr->minHeight = parFmt->minHeight;
  2009.     } else {
  2010.       itemPtr->openSpace = TRUE;
  2011.       itemPtr->keepWithNext = FALSE;
  2012.       itemPtr->keepTogether = FALSE;
  2013.       itemPtr->newPage = FALSE;
  2014.       itemPtr->tabStops = FALSE;
  2015.       itemPtr->minLines = 0;
  2016.       itemPtr->minHeight = 0;
  2017.     }
  2018.     itemPtr->docOwnsData = docOwnsData;
  2019.     itemPtr->notCached = TRUE;
  2020.     itemPtr->neverCached = TRUE;
  2021.   }
  2022. }
  2023.  
  2024. /*****************************************************************************
  2025. *
  2026. *   AppendItem (d, proc, data, docOwnsData, lines,
  2027. *               parFmt, colFmt, font)
  2028. *       Processes user parameters and appends the item to the end of the
  2029. *       item list
  2030. *
  2031. *****************************************************************************/
  2032.  
  2033. extern void AppendItem (DoC d, DocPrntProc proc, Pointer data,
  2034.                         Boolean docOwnsData, Int2 lines,
  2035.                         ParPtr parFmt, ColPtr colFmt, FonT font)
  2036.  
  2037. {
  2038.   DocData   ddata;
  2039.   ItemData  itemData;
  2040.   ItemPtr   itemPtr;
  2041.  
  2042.   if (d != NULL && proc != NULL) {
  2043.     GetPanelExtra ((PaneL) d, &ddata);
  2044.     MemFill (&itemData, 0, sizeof (ItemData));
  2045.     SetupItem (d, &itemData, proc, data, docOwnsData,
  2046.                lines, parFmt, colFmt, font);
  2047.     if (ddata.upd != NULL) {
  2048.       ddata.upd (d, ddata.numItems, 0);
  2049.     }
  2050.     itemPtr = CreateItemPtr (d, ddata.numItems);
  2051.     GetPanelExtra ((PaneL) d, &ddata);
  2052.     if (itemPtr != NULL) {
  2053.       *itemPtr = *(&itemData);
  2054.       itemPtr->startsAt = ddata.numLines;
  2055.       UpdateItemHeights (itemPtr);
  2056.       ddata.numLines += itemPtr->numRows;
  2057.       (ddata.numItems)++;
  2058.       SetPanelExtra ((PaneL) d, &ddata);
  2059.       if (ddata.autoAdjust) {
  2060.         AdjustDocScroll (d);
  2061.       }
  2062.     }
  2063.   }
  2064. }
  2065.  
  2066. /*****************************************************************************
  2067. *
  2068. *   ReplaceItem (d, item, proc, data, docOwnsData,
  2069. *                lines, parFmt, colFmt, font)
  2070. *       Replaces an existing item in a document
  2071. *
  2072. *****************************************************************************/
  2073.  
  2074. extern void ReplaceItem (DoC d, Int2 item, DocPrntProc proc,
  2075.                          Pointer data, Boolean docOwnsData, Int2 lines,
  2076.                          ParPtr parFmt, ColPtr colFmt, FonT font)
  2077.  
  2078. {
  2079.   DocData  ddata;
  2080.   ItemPtr  itemPtr;
  2081.   Int2     startsAt;
  2082.  
  2083.   if (d != NULL && proc != NULL) {
  2084.     GetPanelExtra ((PaneL) d, &ddata);
  2085.     if (item > 0 && item <= ddata.numItems) {
  2086.       item--;
  2087.       if (ddata.upd != NULL) {
  2088.         ddata.upd (d, item, item);
  2089.       }
  2090.       itemPtr = GetItemPtr (&ddata, item);
  2091.       if (itemPtr != NULL) {
  2092.         startsAt = itemPtr->startsAt;
  2093.         itemPtr->text = (CharPtr) MemFree (itemPtr->text);
  2094.         if (itemPtr->docOwnsData) {
  2095.           itemPtr->dataPtr = (Pointer) MemFree (itemPtr->dataPtr);
  2096.         } else {
  2097.           itemPtr->dataPtr = NULL;
  2098.         }
  2099.         itemPtr->extra = MemFree (itemPtr->extra);
  2100.         MemFill (itemPtr, 0, sizeof (ItemData));
  2101.         SetupItem (d, itemPtr, proc, data, docOwnsData,
  2102.                    lines, parFmt, colFmt, font);
  2103.         itemPtr->startsAt = startsAt;
  2104.         UpdateItemHeights (itemPtr);
  2105.         ddata.numLines = UpdateLineStarts (&ddata, item);
  2106.         SetPanelExtra ((PaneL) d, &ddata);
  2107.         if (ddata.autoAdjust) {
  2108.           AdjustDocScroll (d);
  2109.         }
  2110.       }
  2111.     }
  2112.   }
  2113. }
  2114.  
  2115. /*****************************************************************************
  2116. *
  2117. *   InsertItem (d, item, proc, data, docOwnsData,
  2118. *               lines, parFmt, colFmt, font)
  2119. *       Inserts a new item into a document
  2120. *
  2121. *****************************************************************************/
  2122.  
  2123. extern void InsertItem (DoC d, Int2 item, DocPrntProc proc,
  2124.                         Pointer data, Boolean docOwnsData, Int2 lines,
  2125.                         ParPtr parFmt, ColPtr colFmt, FonT font)
  2126.  
  2127. {
  2128.   DocData  ddata;
  2129.   ItemPtr  fromItem;
  2130.   ItemPtr  itemPtr;
  2131.   Int2     j;
  2132.   Int2     startsAt;
  2133.   ItemPtr  toItem;
  2134.  
  2135.   if (d != NULL && proc != NULL) {
  2136.     GetPanelExtra ((PaneL) d, &ddata);
  2137.     if (item > 0 && item <= ddata.numItems) {
  2138.       item--;
  2139.       if (ddata.upd != NULL) {
  2140.         ddata.upd (d, item, 0);
  2141.       }
  2142.       itemPtr = CreateItemPtr (d, ddata.numItems);
  2143.       if (itemPtr != NULL) {
  2144.         GetPanelExtra ((PaneL) d, &ddata);
  2145.         (ddata.numItems)++;
  2146.         SetPanelExtra ((PaneL) d, &ddata);
  2147.         for (j = ddata.numItems - 1; j > item; j--) {
  2148.           fromItem = GetItemPtr (&ddata, j - 1);
  2149.           toItem = GetItemPtr (&ddata, j);
  2150.           if (fromItem != NULL && toItem != NULL) {
  2151.             *toItem = *fromItem;
  2152.           }
  2153.         }
  2154.         itemPtr = GetItemPtr (&ddata, item);
  2155.         if (itemPtr != NULL) {
  2156.           startsAt = itemPtr->startsAt;
  2157.           MemFill (itemPtr, 0, sizeof (ItemData));
  2158.           SetupItem (d, itemPtr, proc, data, docOwnsData,
  2159.                      lines, parFmt, colFmt, font);
  2160.           itemPtr->startsAt = startsAt;
  2161.           UpdateItemHeights (itemPtr);
  2162.           ddata.numLines = UpdateLineStarts (&ddata, item);
  2163.           SetPanelExtra ((PaneL) d, &ddata);
  2164.           if (ddata.autoAdjust) {
  2165.             AdjustDocScroll (d);
  2166.           }
  2167.         }
  2168.       }
  2169.     }
  2170.   }
  2171. }
  2172.  
  2173. /*****************************************************************************
  2174. *
  2175. *   CharPrtProc (ptr)
  2176. *       Standard print function used with AppendText
  2177. *
  2178. *****************************************************************************/
  2179.  
  2180. static CharPtr CharPrtProc (DoC d, Int2 item, Pointer ptr)
  2181.  
  2182. {
  2183.   if (ptr != NULL) {
  2184.     return StringSave ((Nlm_CharPtr)ptr);
  2185.   } else {
  2186.     return NULL;
  2187.   }
  2188. }
  2189.  
  2190. /*****************************************************************************
  2191. *
  2192. *   SkipPastNewLine (text, cnt)
  2193. *       Finds the end of a line of text, up to a maximum number of characters
  2194. *
  2195. *****************************************************************************/
  2196.  
  2197. static Int2 SkipPastNewLine (CharPtr text, Int2 cnt)
  2198.  
  2199. {
  2200.   Char  ch;
  2201.  
  2202.   ch = *(text + cnt);
  2203.   while (ch != '\0' && ch != '\n' && cnt < 16380) {
  2204.     cnt++;
  2205.     ch = *(text + cnt);
  2206.   }
  2207.   while ((ch == '\n' || ch == '\r') && cnt < 16380) {
  2208.     cnt++;
  2209.     ch = *(text + cnt);
  2210.   }
  2211.   return cnt;
  2212. }
  2213.  
  2214. /*****************************************************************************
  2215. *
  2216. *   AppendText (d, text, parFmt, colFmt, font)
  2217. *       Special case of AppendItem that takes formatted text as its data
  2218. *
  2219. *****************************************************************************/
  2220.  
  2221. extern void AppendText (DoC d, CharPtr text, ParPtr parFmt,
  2222.                         ColPtr colFmt, FonT font)
  2223.  
  2224. {
  2225.   Int2     cnt;
  2226.   Int2     cntr;
  2227.   Int2     start;
  2228.   Pointer  txt;
  2229.  
  2230.   if (d != NULL) {
  2231.     if (text != NULL && *text != '\0') {
  2232.       start = 0;
  2233.       cntr = StringLen (text);
  2234.       cnt = MIN (cntr, 16000);
  2235.       cnt = SkipPastNewLine (text + start, cnt);
  2236.       while (cnt > 0) {
  2237.         txt = MemNew (cnt + 1);
  2238.         MemCopy (txt, text + start, cnt);
  2239.         ProgMon ("AppendText");
  2240.         AppendItem (d, CharPrtProc, txt, TRUE, (cnt / 50) + 1,
  2241.                     parFmt, colFmt, font);
  2242.         start += cnt;
  2243.         cntr -= cnt;
  2244.         cnt = MIN (cntr, 16000);
  2245.         cnt = SkipPastNewLine (text + start, cnt);
  2246.       }
  2247.     } else {
  2248.       ProgMon ("AppendText");
  2249.       AppendItem (d, CharPrtProc, "", FALSE, 1,
  2250.                   parFmt, colFmt, font);
  2251.     }
  2252.   }
  2253. }
  2254.  
  2255. /*****************************************************************************
  2256. *
  2257. *   ReplaceText (d, item, text, parFmt, colFmt, font)
  2258. *       Special case of ReplaceItem that takes formatted text as its data
  2259. *
  2260. *****************************************************************************/
  2261.  
  2262. extern void ReplaceText (DoC d, Int2 item, CharPtr text,
  2263.                          ParPtr parFmt, ColPtr colFmt, FonT font)
  2264.  
  2265. {
  2266.   Int2     cnt;
  2267.   Int2     cntr;
  2268.   Int2     start;
  2269.   Pointer  txt;
  2270.  
  2271.   if (d != NULL) {
  2272.     if (text != NULL && *text != '\0') {
  2273.       start = 0;
  2274.       cntr = StringLen (text);
  2275.       cnt = MIN (cntr, 16000);
  2276.       cnt = SkipPastNewLine (text + start, cnt);
  2277.       while (cnt > 0) {
  2278.         txt = MemNew (cnt + 1);
  2279.         MemCopy (txt, text + start, cnt);
  2280.         ReplaceItem (d, item, CharPrtProc, txt, TRUE, (cnt / 50) + 1,
  2281.                      parFmt, colFmt, font);
  2282.         start += cnt;
  2283.         cntr -= cnt;
  2284.         cnt = MIN (cntr, 16000);
  2285.         cnt = SkipPastNewLine (text + start, cnt);
  2286.         item++;
  2287.       }
  2288.     } else {
  2289.       ReplaceItem (d, item, CharPrtProc, "", FALSE, 1,
  2290.                    parFmt, colFmt, font);
  2291.     }
  2292.   }
  2293. }
  2294.  
  2295. /*****************************************************************************
  2296. *
  2297. *   InsertText (d, item, text, parFmt, colFmt, font)
  2298. *       Special case of InsertItem that takes formatted text as its data
  2299. *
  2300. *****************************************************************************/
  2301.  
  2302. extern void InsertText (DoC d, Int2 item, CharPtr text,
  2303.                         ParPtr parFmt, ColPtr colFmt, FonT font)
  2304.  
  2305. {
  2306.   Int2     cnt;
  2307.   Int2     cntr;
  2308.   Int2     start;
  2309.   Pointer  txt;
  2310.  
  2311.   if (d != NULL) {
  2312.     if (text != NULL && *text != '\0') {
  2313.       start = 0;
  2314.       cntr = StringLen (text);
  2315.       cnt = MIN (cntr, 16000);
  2316.       cnt = SkipPastNewLine (text + start, cnt);
  2317.       while (cnt > 0) {
  2318.         txt = MemNew (cnt + 1);
  2319.         MemCopy (txt, text + start, cnt);
  2320.         InsertItem (d, item, CharPrtProc, txt, TRUE, (cnt / 50) + 1,
  2321.                     parFmt, colFmt, font);
  2322.         start += cnt;
  2323.         cntr -= cnt;
  2324.         cnt = MIN (cntr, 16000);
  2325.         cnt = SkipPastNewLine (text + start, cnt);
  2326.         item++;
  2327.       }
  2328.     } else {
  2329.       InsertItem (d, item, CharPrtProc, "", FALSE, 1,
  2330.                   parFmt, colFmt, font);
  2331.     }
  2332.   }
  2333. }
  2334.  
  2335. /*****************************************************************************
  2336. *
  2337. *   DeleteItem (d, item)
  2338. *       Deletes an item from a document
  2339. *
  2340. *****************************************************************************/
  2341.  
  2342. extern void DeleteItem (DoC d, Int2 item)
  2343.  
  2344. {
  2345.   DocData  ddata;
  2346.   ItemPtr  fromItem;
  2347.   ItemPtr  itemPtr;
  2348.   Int2     j;
  2349.   Int2     startsAt;
  2350.   ItemPtr  toItem;
  2351.  
  2352.   if (d != NULL) {
  2353.     GetPanelExtra ((PaneL) d, &ddata);
  2354.     if (item > 0 && item <= ddata.numItems) {
  2355.       item--;
  2356.       itemPtr = GetItemPtr (&ddata, item);
  2357.       if (itemPtr != NULL) {
  2358.         startsAt = itemPtr->startsAt;
  2359.         itemPtr->text = (CharPtr) MemFree (itemPtr->text);
  2360.         if (itemPtr->docOwnsData) {
  2361.           itemPtr->dataPtr = (Pointer) MemFree (itemPtr->dataPtr);
  2362.         } else {
  2363.           itemPtr->dataPtr = NULL;
  2364.         }
  2365.         itemPtr->extra = MemFree (itemPtr->extra);
  2366.         for (j = item; j < ddata.numItems - 1; j++) {
  2367.           fromItem = GetItemPtr (&ddata, j + 1);
  2368.           toItem = GetItemPtr (&ddata, j);
  2369.           if (fromItem != NULL && toItem != NULL) {
  2370.             *toItem = *fromItem;
  2371.           }
  2372.         }
  2373.         itemPtr->startsAt = startsAt;
  2374.         (ddata.numItems)--;
  2375.         ddata.numLines = UpdateLineStarts (&ddata, item);
  2376.         SetPanelExtra ((PaneL) d, &ddata);
  2377.         if (ddata.autoAdjust) {
  2378.           AdjustDocScroll (d);
  2379.         }
  2380.       }
  2381.     }
  2382.   }
  2383. }
  2384.  
  2385. /*****************************************************************************
  2386. *
  2387. *   ResetDocument (d)
  2388. *       Performs garbage collection on document data
  2389. *
  2390. *****************************************************************************/
  2391.  
  2392. static void ResetDocument (PaneL d)
  2393.  
  2394. {
  2395.   DocData    ddata;
  2396.   Int2       i;
  2397.   ItemPtr    itemPtr;
  2398.   MasterPtr  masterPtr;
  2399.   RecT       r;
  2400.  
  2401.   GetPanelExtra (d, &ddata);
  2402.   if (ddata.data != NULL && ddata.cleanup != NULL) {
  2403.     ddata.cleanup ((DoC) d, ddata.data);
  2404.   }
  2405.   if (ddata.upd != NULL) {
  2406.     ddata.upd ((DoC) d, 0, 0);
  2407.   }
  2408.   ObjectRect (d, &r);
  2409.   InsetRect (&r, 4, 4);
  2410.   for (i = 0; i < ddata.numItems; i++) {
  2411.     itemPtr = GetItemPtr (&ddata, i);
  2412.     if (itemPtr != NULL) {
  2413.       itemPtr->text = (CharPtr) MemFree (itemPtr->text);
  2414.       if (itemPtr->docOwnsData) {
  2415.         itemPtr->dataPtr = (Pointer) MemFree (itemPtr->dataPtr);
  2416.       } else {
  2417.         itemPtr->dataPtr = NULL;
  2418.       }
  2419.       itemPtr->extra = MemFree (itemPtr->extra);
  2420.     }
  2421.   }
  2422.   if (ddata.master != NULL) {
  2423.     masterPtr = ddata.master;
  2424.     for (i = 0; i < MAXLISTS; i++) {
  2425.       masterPtr->list [i] = (Nlm_ListPtr)MemFree (masterPtr->list [i]);
  2426.     }
  2427.   }
  2428.   ddata.colFmts = ValNodeFreeData (ddata.colFmts);
  2429.   ddata.numItems = 0;
  2430.   ddata.numLines = 0;
  2431.   ddata.barmax = 0;
  2432.   ddata.master = (MasterPtr) MemFree (ddata.master);
  2433.   for (i = 0; i < MAXFONTS; i++) {
  2434.     fontHeights [i].font = NULLFONT;
  2435.     fontHeights [i].height = 0;
  2436.   }
  2437.   ddata.data = NULL;
  2438.   ddata.cleanup = NULL;
  2439.   SetPanelExtra ((PaneL) d, &ddata);
  2440. }
  2441.  
  2442. /*****************************************************************************
  2443. *
  2444. *   NewDocument (d)
  2445. *       Initialized document panel extra data
  2446. *
  2447. *****************************************************************************/
  2448.  
  2449. static void NewDocument (DoC d)
  2450.  
  2451. {
  2452.   DocData  ddata;
  2453.   Int2     i;
  2454.  
  2455.   ddata.numItems = 0;
  2456.   ddata.numLines = 0;
  2457.   ddata.barmax = 0;
  2458.   ddata.tabCount = 4;
  2459.   ddata.autoAdjust = TRUE;
  2460.   ddata.isvirtual = FALSE;
  2461.   ddata.doc = d;
  2462.   ddata.master = NULL;
  2463.   ddata.draw = NULL;
  2464.   ddata.pan = NULL;
  2465.   ddata.gray = NULL;
  2466.   ddata.invert = NULL;
  2467.   ddata.color = NULL;
  2468.   ddata.put = NULL;
  2469.   ddata.get = NULL;
  2470.   ddata.upd = NULL;
  2471.   ddata.data = NULL;
  2472.   ddata.cleanup = NULL;
  2473.   ddata.colFmts = NULL;
  2474.   for (i = 0; i < MAXFONTS; i++) {
  2475.     fontHeights [i].font = NULLFONT;
  2476.     fontHeights [i].height = 0;
  2477.   }
  2478.   SetPanelExtra ((PaneL) d, &ddata);
  2479. }
  2480.  
  2481. /*****************************************************************************
  2482. *
  2483. *   DocumentPanel (prnt, pixwidth, pixheight)
  2484. *       Creates an empty document object
  2485. *
  2486. *****************************************************************************/
  2487.  
  2488. extern DoC DocumentPanel (GrouP prnt, Int2 pixwidth, Int2 pixheight)
  2489.  
  2490. {
  2491.   DoC  d;
  2492.   WindoW    tempPort;
  2493.  
  2494.   d = NULLFONT;
  2495.   if (prnt != NULL) {
  2496.     tempPort = SavePort (prnt);
  2497.     d = (DoC) AutonomousPanel (prnt, pixwidth, pixheight, DrawDocument,
  2498.                                DocumentScrlProc, NULL, sizeof (DocData),
  2499.                                ResetDocument, NULL);
  2500.     if (d != NULL) {
  2501.       NewDocument (d);
  2502.     }
  2503.     RestorePort (tempPort);
  2504.   }
  2505.   return d;
  2506. }
  2507.  
  2508. /*****************************************************************************
  2509. *
  2510. *   SetDocProcs (d, click, drag, release, pan)
  2511. *       Sets mouse callbacks for a document object
  2512. *
  2513. *****************************************************************************/
  2514.  
  2515. extern void SetDocProcs (DoC d, DocClckProc click, DocClckProc drag,
  2516.                          DocClckProc release, DocPanProc pan)
  2517.  
  2518. {
  2519.   DocData  ddata;
  2520.  
  2521.   if (d != NULL) {
  2522.     Nlm_SetPanelClick ((PaneL) d, (PnlClckProc) click, (PnlClckProc) drag,
  2523.                        NULL, (PnlClckProc) release);
  2524.     GetPanelExtra ((PaneL) d, &ddata);
  2525.     ddata.pan = pan;
  2526.     SetPanelExtra ((PaneL) d, &ddata);
  2527.   }
  2528. }
  2529.  
  2530. /*****************************************************************************
  2531. *
  2532. *   SetDocShade (d, draw, gray, invert, color)
  2533. *       Sets draw callbacks for a document object
  2534. *
  2535. *****************************************************************************/
  2536.  
  2537. extern void SetDocShade (DoC d, DocDrawProc draw, DocShadeProc gray,
  2538.                          DocShadeProc invert, DocShadeProc color)
  2539.  
  2540. {
  2541.   DocData  ddata;
  2542.  
  2543.   if (d != NULL) {
  2544.     GetPanelExtra ((PaneL) d, &ddata);
  2545.     ddata.draw = draw;
  2546.     ddata.gray = gray;
  2547.     ddata.invert = invert;
  2548.     ddata.color = color;
  2549.     SetPanelExtra ((PaneL) d, &ddata);
  2550.   }
  2551. }
  2552.  
  2553. /*****************************************************************************
  2554. *
  2555. *   SetDocCache (d, put, get, upd)
  2556. *       Sets cache callbacks for a document object
  2557. *
  2558. *****************************************************************************/
  2559.  
  2560. extern void SetDocCache (DoC d, DocPutProc put, DocGetProc get, DocUpdProc upd)
  2561.  
  2562. {
  2563.   DocData  ddata;
  2564.  
  2565.   if (d != NULL) {
  2566.     GetPanelExtra ((PaneL) d, &ddata);
  2567.     ddata.put = put;
  2568.     ddata.get = get;
  2569.     ddata.upd = upd;
  2570.     SetPanelExtra ((PaneL) d, &ddata);
  2571.   }
  2572. }
  2573.  
  2574. /*****************************************************************************
  2575. *
  2576. *   SetDocData (d, data, cleanup)
  2577. *       Attaches instance data to a document object
  2578. *
  2579. *****************************************************************************/
  2580.  
  2581. void SetDocData (DoC d, VoidPtr data, DocFreeProc cleanup)
  2582.  
  2583. {
  2584.   DocData  ddata;
  2585.  
  2586.   if (d != NULL) {
  2587.     GetPanelExtra ((PaneL) d, &ddata);
  2588.     ddata.data = data;
  2589.     ddata.cleanup = cleanup;
  2590.     SetPanelExtra ((PaneL) d, &ddata);
  2591.   }
  2592. }
  2593.  
  2594. /*****************************************************************************
  2595. *
  2596. *   GetDocData (d)
  2597. *       Returns the instance data attached to a document object
  2598. *
  2599. *****************************************************************************/
  2600.  
  2601. VoidPtr GetDocData (DoC d)
  2602.  
  2603. {
  2604.   DocData  ddata;
  2605.  
  2606.   if (d != NULL) {
  2607.     GetPanelExtra ((PaneL) d, &ddata);
  2608.     return (ddata.data);
  2609.   } else {
  2610.     return NULL;
  2611.   }
  2612. }
  2613.  
  2614. /*****************************************************************************
  2615. *
  2616. *   GetDocParams (d, numItems, numLines)
  2617. *       Returns document-specific information
  2618. *
  2619. *****************************************************************************/
  2620.  
  2621. void GetDocParams (DoC d, Int2Ptr numItems, Int2Ptr numLines)
  2622.  
  2623. {
  2624.   DocData  ddata;
  2625.   Int2     items;
  2626.   Int2     lines;
  2627.  
  2628.   items = 0;
  2629.   lines = 0;
  2630.   if (d != NULL) {
  2631.     GetPanelExtra ((PaneL) d, &ddata);
  2632.     items = ddata.numItems;
  2633.     lines = ddata.numLines;
  2634.   }
  2635.   if (numItems != NULL) {
  2636.     *numItems = items;
  2637.   }
  2638.   if (numLines != NULL) {
  2639.     *numLines = lines;
  2640.   }
  2641. }
  2642.  
  2643. /*****************************************************************************
  2644. *
  2645. *   GetItemParams (d, item, startsAt, numRows, numCols, lineHeight)
  2646. *       Returns item-specific information
  2647. *
  2648. *****************************************************************************/
  2649.  
  2650. void GetItemParams (DoC d, Int2 item, Int2Ptr startsAt, Int2Ptr numRows,
  2651.                     Int2Ptr numCols, Int2Ptr lineHeight)
  2652.  
  2653. {
  2654.   Int2     cols;
  2655.   Int2     first;
  2656.   DocData  ddata;
  2657.   Int2     height;
  2658.   ItemPtr  itemPtr;
  2659.   Int2     rows;
  2660.  
  2661.   cols = 0;
  2662.   first = 0;
  2663.   height = 0;
  2664.   rows = 0;
  2665.   if (d != NULL && item > 0) {
  2666.     GetPanelExtra ((PaneL) d, &ddata);
  2667.     itemPtr = GetItemPtr (&ddata, item - 1);
  2668.     if (itemPtr != NULL) {
  2669.       first = itemPtr->startsAt;
  2670.       rows = itemPtr->numRows;
  2671.       cols = itemPtr->numCols;
  2672.       height = itemPtr->lineHeight;
  2673.     }
  2674.   }
  2675.   if (startsAt != NULL) {
  2676.     *startsAt = first;
  2677.   }
  2678.   if (numRows != NULL) {
  2679.     *numRows = rows;
  2680.   }
  2681.   if (numCols != NULL) {
  2682.     *numCols = cols;
  2683.   }
  2684.   if (lineHeight != NULL) {
  2685.     *lineHeight = height;
  2686.   }
  2687. }
  2688.  
  2689. /*****************************************************************************
  2690. *
  2691. *   GetColParams (d, item, col, pixPos, pixWidth, pixInset, just)
  2692. *       Returns column-specific information
  2693. *
  2694. *****************************************************************************/
  2695.  
  2696. void GetColParams (DoC d, Int2 item, Int2 col, Int2Ptr pixPos,
  2697.                    Int2Ptr pixWidth, Int2Ptr pixInset, CharPtr just)
  2698.  
  2699. {
  2700.   ColXPtr  colFmt;
  2701.   DocData  ddata;
  2702.   Int2     inset;
  2703.   ItemPtr  itemPtr;
  2704.   Char     jst;
  2705.   Int2     position;
  2706.   RecT     r;
  2707.   Int2     width;
  2708.  
  2709.   inset = 0;
  2710.   position = 0;
  2711.   width = 0;
  2712.   jst = 'l';
  2713.   if (d != NULL && item > 0 && col > 0) {
  2714.     GetPanelExtra ((PaneL) d, &ddata);
  2715.     ObjectRect (d, &r);
  2716.     InsetRect (&r, 4, 4);
  2717.     itemPtr = GetItemPtr (&ddata, item - 1);
  2718.     if (itemPtr != NULL && col <itemPtr->numCols + 1) {
  2719.       colFmt = itemPtr->colFmt;
  2720.       if (colFmt != NULL) {
  2721.         SetTablePixFormat (colFmt, r.left, itemPtr->numCols);
  2722.         position = colFmt [col - 1].position;
  2723.         width = colFmt [col - 1].pixWidth;
  2724.         inset = colFmt [col - 1].pixInset;
  2725.         jst = justToChar [colFmt [col - 1].just];
  2726.       }
  2727.     }
  2728.   }
  2729.   if (pixPos != NULL) {
  2730.     *pixPos = position;
  2731.   }
  2732.   if (pixWidth != NULL) {
  2733.     *pixWidth = width;
  2734.   }
  2735.   if (pixInset != NULL) {
  2736.     *pixInset = inset;
  2737.   }
  2738.   if (just != NULL) {
  2739.     *just = jst;
  2740.   }
  2741. }
  2742.  
  2743. /*****************************************************************************
  2744. *
  2745. *   MapDocPoint (d, pt, item, row, col, rct)
  2746. *       Converts a mouse point to a item, row, and column positions
  2747. *       within a document
  2748. *
  2749. *****************************************************************************/
  2750.  
  2751. extern void MapDocPoint (DoC d, PoinT pt, Int2Ptr item, Int2Ptr row, Int2Ptr col, RectPtr rct)
  2752.  
  2753. {
  2754.   Int2     cl;
  2755.   ColXPtr  colFmt;
  2756.   DocData  ddata;
  2757.   Int2     firstItem;
  2758.   Int2     firstLine;
  2759.   Boolean  goOn;
  2760.   Int2     i;
  2761.   Int2     itemNum;
  2762.   ItemPtr  itemPtr;
  2763.   Int2     itm;
  2764.   Int2     leadHeight;
  2765.   Int2     lineHeight;
  2766.   Int2     numCols;
  2767.   Int2     numRows;
  2768.   Int2     off;
  2769.   RecT     q;
  2770.   RecT     r;
  2771.   RecT     rc;
  2772.   Int2     rw;
  2773.   BaR      sb;
  2774.  
  2775.   itm = 0;
  2776.   rw = 0;
  2777.   cl = 0;
  2778.   LoadRect (&rc, 0, 0, 0, 0);
  2779.   if (d != NULL) {
  2780.     GetPanelExtra ((PaneL) d, &ddata);
  2781.     ObjectRect (d, &r);
  2782.     InsetRect (&r, 4, 4);
  2783.     if (PtInRect (pt, &r)) {
  2784.       sb = GetSlateVScrollBar ((SlatE) d);
  2785.       if (sb != NULL) {
  2786.         goOn = TRUE;
  2787.         LoadRect (&q, r.left, r.top, r.right, r.top);
  2788.         off = GetValue (sb);
  2789.         itemNum = GetItemNum (&ddata, off);
  2790.         itemPtr = GetItemPtr (&ddata, itemNum);
  2791.         if (itemPtr != NULL) {
  2792.           firstLine = off - itemPtr->startsAt;
  2793.           firstItem = itemNum;
  2794.           while (goOn && itemNum < ddata.numItems) {
  2795.             itemPtr = GetItemPtr (&ddata, itemNum);
  2796.             if (itemPtr != NULL) {
  2797.               CacheIfNever (&ddata, itemNum + 1, itemPtr, &r, ddata.tabCount);
  2798.               SetTablePixFormat (itemPtr->colFmt, r.left, itemPtr->numCols);
  2799.               if (itemNum > firstItem) {
  2800.                 leadHeight = itemPtr->leadHeight;
  2801.               } else {
  2802.                 leadHeight = 0;
  2803.               }
  2804.               lineHeight = itemPtr->lineHeight;
  2805.               numRows = MIN (itemPtr->numRows - firstLine,
  2806.                              MAX ((r.bottom - q.top - leadHeight) / lineHeight, 0));
  2807.               numCols = itemPtr->numCols;
  2808.               colFmt = itemPtr->colFmt;
  2809.               q.bottom = q.top + leadHeight + lineHeight * numRows;
  2810.               if (PtInRect (pt, &q) && numRows > 0) {
  2811.                 goOn = FALSE;
  2812.                 itm = itemNum + 1;
  2813.                 if (pt.y <= q.top + leadHeight) {
  2814.                   rw = 0;
  2815.                 } else {
  2816.                   rw = firstLine + ((pt.y - q.top - leadHeight) / lineHeight) + 1;
  2817.                 }
  2818.                 if (numCols > 0 && colFmt != NULL) {
  2819.                   for (i = 0; i < numCols; i++) {
  2820.                     if (pt.x >= colFmt [i].position &&
  2821.                         pt.x < colFmt [i].position + colFmt [i].pixWidth) {
  2822.                       cl = i + 1;
  2823.                       if (rw > 0) {
  2824.                         rc.left = colFmt [i].position;
  2825.                         rc.top = q.top + leadHeight + lineHeight * (rw - firstLine - 1);
  2826.                         rc.right = rc.left + colFmt [i].pixWidth;
  2827.                         rc.bottom = rc.top + lineHeight;
  2828.                       }
  2829.                     }
  2830.                   }
  2831.                 }
  2832.               } else {
  2833.                 q.top = q.bottom;
  2834.               }
  2835.               if (numRows < itemPtr->numRows - firstLine) {
  2836.                 goOn = FALSE;
  2837.               }
  2838.             }
  2839.             itemNum++;
  2840.             firstLine = 0;
  2841.           }
  2842.         }
  2843.       }
  2844.     }
  2845.   }
  2846.   if (item != NULL) {
  2847.     *item = itm;
  2848.   }
  2849.   if (row != NULL) {
  2850.     *row = rw;
  2851.   }
  2852.   if (col != NULL) {
  2853.     *col = cl;
  2854.   }
  2855.   if (rct != NULL) {
  2856.     *rct = rc;
  2857.   }
  2858. }
  2859.  
  2860. /*****************************************************************************
  2861. *
  2862. *   GetDocText (d, item, row, col)
  2863. *       Returns a string with text from a document.  If item, row, or col
  2864. *       parameters are 0, text is taken from any item, row, or column,
  2865. *       respectively.  The string must be freed by the application
  2866. *
  2867. *****************************************************************************/
  2868.  
  2869. extern CharPtr GetDocText (DoC d, Int2 item, Int2 row, Int2 col)
  2870.  
  2871. {
  2872.   ByteStorePtr  bsp;
  2873.   Char          ch;
  2874.   Int2          cl;
  2875.   DocData       ddata;
  2876.   Int2          i;
  2877.   ItemData      itemData;
  2878.   ItemPtr       itemPtr;
  2879.   Int2          k;
  2880.   Int2          num;
  2881.   CharPtr       ptr;
  2882.   RecT          r;
  2883.   Int2          rw;
  2884.   Int2          start;
  2885.   Int2          stop;
  2886.   CharPtr       text;
  2887.  
  2888.   text = NULL;
  2889.   if (d != NULL && item >= 0 && row >= 0 && col >= 0) {
  2890.     ObjectRect (d, &r);
  2891.     InsetRect (&r, 4, 4);
  2892.     GetPanelExtra ((PaneL) d, &ddata);
  2893.     if (ddata.numItems > 0) {
  2894.       bsp = BSNew (0);
  2895.       if (bsp != NULL) {
  2896.         if (item == 0) {
  2897.           start = 0;
  2898.           stop = ddata.numItems;
  2899.         } else if (item <= ddata.numItems) {
  2900.           start = item - 1;
  2901.           stop = item;
  2902.         } else {
  2903.           start = 0;
  2904.           stop = 0;
  2905.         }
  2906.         for (i = start; i < stop; i++) {
  2907.           itemPtr = GetItemPtr (&ddata, i);
  2908.           if (itemPtr != NULL) {
  2909.             itemData.text = NULL;
  2910.             itemData.prtProc = itemPtr->prtProc;
  2911.             itemData.dataPtr = itemPtr->dataPtr;
  2912.             itemData.font = itemPtr->font;
  2913.             itemData.extra = itemPtr->extra;
  2914.             itemData.openSpace = itemPtr->openSpace;
  2915.             itemData.tabStops = itemPtr->tabStops;
  2916.             itemData.numRows = itemPtr->numRows;
  2917.             itemData.numCols = itemPtr->numCols;
  2918.             itemData.minLines = itemPtr->minLines;
  2919.             itemData.minHeight = itemPtr->minHeight;
  2920.             itemData.colFmt = itemPtr->colFmt;
  2921.             SetTablePixFormat (itemData.colFmt, r.left, itemData.numCols);
  2922.             if (itemData.prtProc != NULL) {
  2923.               FormatText (&ddata, i, &itemData, TRUE, ddata.tabCount);
  2924.               SetTablePixFormat (itemData.colFmt, r.left, itemData.numCols);
  2925.               text = itemData.text;
  2926.               if (text != NULL && *text != '\0' && itemData.colFmt != NULL) {
  2927.                 if (i > start && itemData.openSpace > 0 && item == 0) {
  2928.                   BSPutByte (bsp, (Int2) '\n');
  2929.                 }
  2930.                 rw = 0;
  2931.                 cl = 0;
  2932.                 ptr = text;
  2933.                 ch = *ptr;
  2934.                 while (ch != '\0') {
  2935.                   if (ch == '\n') {
  2936.                     if ((rw + 1 == row && col == 0) || row == 0) {
  2937.                       BSPutByte (bsp, (Int2) '\n');
  2938.                     }
  2939.                     cl = 0;
  2940.                     rw++;
  2941.                     ptr++;
  2942.                   } else if (ch == '\t') {
  2943.                     if ((rw + 1 == row || row == 0) && col == 0) {
  2944.                       BSPutByte (bsp, (Int2) '\t');
  2945.                     }
  2946.                     cl++;
  2947.                     ptr++;
  2948.                   } else {
  2949.                     num = 0;
  2950.                     while (ch != '\0' && ch != '\t' && ch != '\n') {
  2951.                       num++;
  2952.                       ch = ptr [num];
  2953.                     }
  2954.                     if (num > 0 && (cl +1 == col || col == 0) &&
  2955.                         (rw + 1 == row || row == 0)) {
  2956.                       for (k = 0; k < num; k++) {
  2957.                         BSPutByte (bsp, (Int2) ptr [k]);
  2958.                       }
  2959.                     }
  2960.                     ptr += num;
  2961.                   }
  2962.                   ch = *ptr;
  2963.                 }
  2964.               }
  2965.             }
  2966.             MemFree (itemData.text);
  2967.           }
  2968.         }
  2969.         text = (Nlm_CharPtr) BSMerge (bsp, NULL);
  2970.         BSFree (bsp);
  2971.       }
  2972.     }
  2973.   }
  2974.   return text;
  2975. }
  2976.  
  2977. /*****************************************************************************
  2978. *
  2979. *   ItemIsVisible (d, item, top, bottom, firstLine)
  2980. *       Finds the visible region of an item in a document
  2981. *
  2982. *****************************************************************************/
  2983.  
  2984. extern Boolean ItemIsVisible (DoC d, Int2 item, Int2Ptr top,
  2985.                               Int2Ptr bottom, Int2Ptr firstLine)
  2986.  
  2987. {
  2988.   DocData  ddata;
  2989.   Int2     firstItem;
  2990.   Int2     fstLine;
  2991.   Boolean  goOn;
  2992.   Int2     itemNum;
  2993.   ItemPtr  itemPtr;
  2994.   Int2     leadHeight;
  2995.   Int2     lineHeight;
  2996.   Int2     numRows;
  2997.   Int2     off;
  2998.   RecT     r;
  2999.   RecT     rct;
  3000.   Boolean  rsult;
  3001.   BaR      sb;
  3002.  
  3003.   rsult = FALSE;
  3004.   if (top != NULL) {
  3005.     *top = 0;
  3006.   }
  3007.   if (bottom != NULL) {
  3008.     *bottom = 0;
  3009.   }
  3010.   if (firstLine != NULL) {
  3011.    *firstLine = 0;
  3012.   }
  3013.   if (d != NULL) {
  3014.     ObjectRect (d, &r);
  3015.     InsetRect (&r, 4, 4);
  3016.     GetPanelExtra ((PaneL) d, &ddata);
  3017.     sb = GetSlateVScrollBar ((SlatE) d);
  3018.     if (item > 0 && item <= ddata.numItems && sb != NULL) {
  3019.       item--;
  3020.       goOn = TRUE;
  3021.       LoadRect (&rct, r.left, r.top, r.right, r.top);
  3022.       off = GetValue (sb);
  3023.       itemNum = GetItemNum (&ddata, off);
  3024.       itemPtr = GetItemPtr (&ddata, itemNum);
  3025.       if (itemPtr != NULL) {
  3026.         fstLine = off - itemPtr->startsAt;
  3027.         firstItem = itemNum;
  3028.         lineHeight = 0;
  3029.         leadHeight = 0;
  3030.         numRows = 0;
  3031.         while (goOn && itemNum < ddata.numItems && itemNum <= item) {
  3032.           itemPtr = GetItemPtr (&ddata, itemNum);
  3033.           if (itemPtr != NULL) {
  3034.             CacheIfNever (&ddata, itemNum + 1, itemPtr, &r, ddata.tabCount);
  3035.             SetTablePixFormat (itemPtr->colFmt, r.left, itemPtr->numCols);
  3036.             if (itemNum > firstItem) {
  3037.               leadHeight = itemPtr->leadHeight;
  3038.             } else {
  3039.               leadHeight = 0;
  3040.             }
  3041.             lineHeight = itemPtr->lineHeight;
  3042.             rct.top += leadHeight;
  3043.             numRows = MIN (itemPtr->numRows,
  3044.                            MAX ((r.bottom - rct.top) / lineHeight, 0));
  3045.             rct.bottom = rct.top + lineHeight * (numRows - fstLine);
  3046.             if (itemNum == item) {
  3047.               goOn = FALSE;
  3048.               if (numRows > 0) {
  3049.                 if (top != NULL) {
  3050.                   *top = rct.top;
  3051.                 }
  3052.                 if (bottom != NULL) {
  3053.                   *bottom = rct.bottom;
  3054.                 }
  3055.                 if (firstLine != NULL) {
  3056.                   *firstLine = fstLine;
  3057.                 }
  3058.                 rsult = TRUE;
  3059.               }
  3060.             } else {
  3061.               rct.top = rct.bottom;
  3062.             }
  3063.             if (numRows < itemPtr->numRows) {
  3064.               goOn = FALSE;
  3065.             }
  3066.           }
  3067.           itemNum++;
  3068.           fstLine = 0;
  3069.         }
  3070.       }
  3071.     }
  3072.   }
  3073.   return rsult;
  3074. }
  3075.  
  3076. /*****************************************************************************
  3077. *
  3078. *   GetScrlParams (d, offset, firstShown, firstLine)
  3079. *       Returns scroll-specific information
  3080. *
  3081. *****************************************************************************/
  3082.  
  3083. extern Boolean GetScrlParams (DoC d, Int2Ptr offset,
  3084.                               Int2Ptr firstShown, Int2Ptr firstLine)
  3085.  
  3086. {
  3087.   DocData  ddata;
  3088.   Int2     item;
  3089.   Int2     line;
  3090.   Int2     off;
  3091.   Boolean  rsult;
  3092.   BaR      sb;
  3093.  
  3094.   rsult = FALSE;
  3095.   off = 0;
  3096.   item = 0;
  3097.   line = 0;
  3098.   if (d != NULL) {
  3099.     GetPanelExtra ((PaneL) d, &ddata);
  3100.     sb = GetSlateVScrollBar ((SlatE) d);
  3101.     if (sb != NULL) {
  3102.       off = GetValue (sb);
  3103.       item = GetItemNum (&ddata, off);
  3104.       line = off - GetStartsAt (&ddata, item);
  3105.       rsult = TRUE;
  3106.     }
  3107.   }
  3108.   if (offset != NULL) {
  3109.     *offset = off;
  3110.   }
  3111.   if (firstShown != NULL) {
  3112.     *firstShown = item + 1;
  3113.   }
  3114.   if (firstLine != NULL) {
  3115.     *firstLine = line;
  3116.   }
  3117.   return rsult;
  3118. }
  3119.  
  3120. /*****************************************************************************
  3121. *
  3122. *   UpdateDocument (d, from, to)
  3123. *       Invalidates and updates items in a document
  3124. *
  3125. *****************************************************************************/
  3126.  
  3127. extern void UpdateDocument (DoC d, Int2 from, Int2 to)
  3128.  
  3129. {
  3130.   Int2     bottom;
  3131.   DocData  ddata;
  3132.   Int2     item;
  3133.   ItemPtr  itemPtr;
  3134.   RecT     r;
  3135.   Int2     start;
  3136.   Int2     stop;
  3137.   Int2     swap;
  3138.   WindoW   tempPort;
  3139.   Int2     top;
  3140.  
  3141.   if (d != NULL && from >= 0 && to >= 0) {
  3142.     GetPanelExtra ((PaneL) d, &ddata);
  3143.     if (from == 0 || from > ddata.numItems) {
  3144.       start = 0;
  3145.       from = 0;
  3146.     } else {
  3147.       start = from - 1;
  3148.     }
  3149.     if (to == 0 || to > ddata.numItems) {
  3150.       stop = ddata.numItems;
  3151.       to = ddata.numItems;
  3152.     } else {
  3153.       stop = to;
  3154.     }
  3155.     for (item = start; item < stop; item++) {
  3156.       itemPtr = GetItemPtr (&ddata,item);
  3157.       if (itemPtr != NULL) {
  3158.         itemPtr->text = (CharPtr) MemFree (itemPtr->text);
  3159.         itemPtr->notCached = TRUE;
  3160.         itemPtr->neverCached = TRUE;
  3161.       }
  3162.     }
  3163.     if (ddata.upd != NULL) {
  3164.       ddata.upd (d, MIN (from, to), MAX (from, to));
  3165.     }
  3166.     if (Enabled (d) && AllParentsEnabled (d) &&
  3167.         Visible (d) && AllParentsVisible (d)) {
  3168.       tempPort = SavePort (d);
  3169.       ObjectRect (d, &r);
  3170.       InsetRect (&r, 4, 4);
  3171.       Select (d);
  3172.       if (from > to && from != 0 && to != ddata.numItems) {
  3173.         swap = from;
  3174.         from = to;
  3175.         to = swap;
  3176.       }
  3177.       if (from > 0 && from <= ddata.numItems &&
  3178.           ItemIsVisible (d, from, &top, NULL, NULL)) {
  3179.         r.top = top;
  3180.       }
  3181.       if (to > 0 && to < ddata.numItems &&
  3182.           ItemIsVisible (d, to, NULL, &bottom, NULL)) {
  3183.         r.bottom = bottom;
  3184.       }
  3185.       InsetRect (&r, -1, -1);
  3186.       InvalRect (&r);
  3187.       RestorePort (tempPort);
  3188.     }
  3189.     AdjustDocScroll (d);
  3190.   }
  3191. }
  3192.  
  3193. /*****************************************************************************
  3194. *
  3195. *   SaveTableItem (itemPtr, f, tabStops, tabCount)
  3196. *       Reformats and saves an item to a file
  3197. *
  3198. *****************************************************************************/
  3199.  
  3200. static void SaveTableItem (ItemPtr itemPtr, FILE *f,
  3201.                            Boolean tabStops, Int2 tabCount)
  3202.  
  3203. {
  3204.   Char     ch;
  3205.   Int2     col;
  3206.   ColXPtr  colFmt;
  3207.   Int2     i;
  3208.   Int2     insetLeft;
  3209.   Int2     insetRight;
  3210.   Char     just;
  3211.   Int2     next;
  3212.   Int2     num;
  3213.   Int2     pos;
  3214.   CharPtr  ptr;
  3215.   Int2     row;
  3216.   CharPtr  text;
  3217.  
  3218.   if (itemPtr != NULL && f != NULL) {
  3219.     text = itemPtr->text;
  3220.     colFmt = itemPtr->colFmt;
  3221.     if (text != NULL && *text != '\0' && colFmt != NULL) {
  3222.       pos = 0;
  3223.       row = 0;
  3224.       col = 0;
  3225.       ptr = text;
  3226.       ch = *ptr;
  3227.       while (ch != '\0') {
  3228.         if (ch == '\n') {
  3229.           col = 0;
  3230.           row++;
  3231.           ptr++;
  3232.           pos = 0;
  3233.           fputc ('\n', f);
  3234.         } else if (ch == '\t' && (! tabStops)) {
  3235.           col++;
  3236.           ptr++;
  3237.         } else  {
  3238.           num = 0;
  3239.           while (ch != '\0' && (ch != '\t' || tabStops) && ch != '\n') {
  3240.             num++;
  3241.             ch = ptr [num];
  3242.           }
  3243.           if (num > 0 && col < itemPtr->numCols) {
  3244.             just = justToChar [colFmt [col].just];
  3245.             if (just == 'c') {
  3246.               insetLeft = colFmt [col].charInset;
  3247.               insetRight = colFmt [col].charInset;
  3248.             } else if (just == 'l') {
  3249.               insetLeft = colFmt [col].charInset;
  3250.               insetRight = 0;
  3251.             } else if (just == 'r') {
  3252.               insetLeft = 0;
  3253.               insetRight = colFmt [col].charInset;
  3254.             } else {
  3255.               insetLeft = 0;
  3256.               insetRight = 0;
  3257.             }
  3258.             next = colFmt [col].position + insetLeft;
  3259.             while (num > 0 && *ptr == '\t') {
  3260.               num--;
  3261.               ptr++;
  3262.               next += tabCount;
  3263.             }
  3264.             while (pos < next) {
  3265.               fputc (' ', f);
  3266.               pos++;
  3267.             }
  3268.             if (just == 'r') {
  3269.               next = colFmt [col].position + colFmt [col].charWidth -
  3270.                      insetRight - num;
  3271.               while (pos < next) {
  3272.                 fputc (' ', f);
  3273.                 pos++;
  3274.               }
  3275.             } else if (just == 'c') {
  3276.               next = colFmt [col].position + colFmt [col].charWidth -
  3277.                      insetRight - num / 2;
  3278.               while (pos < next) {
  3279.                 fputc (' ', f);
  3280.                 pos++;
  3281.               }
  3282.             }
  3283.             for (i = 0; i < num; i++) {
  3284.               fputc (ptr [i], f);
  3285.               pos++;
  3286.             }
  3287.           }
  3288.           ptr += num;
  3289.         }
  3290.         ch = *ptr;
  3291.       }
  3292.     }
  3293.   }
  3294. }
  3295.  
  3296. /*****************************************************************************
  3297. *
  3298. *   SaveDocument (d, f)
  3299. *       Saves all document items to a file
  3300. *
  3301. *****************************************************************************/
  3302.  
  3303. extern void SaveDocument (DoC d, FILE *f)
  3304.  
  3305. {
  3306.   DocData   ddata;
  3307.   Int2      i;
  3308.   ItemData  itemData;
  3309.   ItemPtr   itemPtr;
  3310.  
  3311.   if (d != NULL && f != NULL) {
  3312.     GetPanelExtra ((PaneL) d, &ddata);
  3313.     ddata.isvirtual = FALSE;
  3314.     ddata.put = NULL;
  3315.     ddata.get = NULL;
  3316.     ddata.upd = NULL;
  3317.     for (i = 0; i < ddata.numItems; i++) {
  3318.       itemPtr = GetItemPtr (&ddata, i);
  3319.       if (itemPtr != NULL) {
  3320.         itemData.text = NULL;
  3321.         itemData.prtProc = itemPtr->prtProc;
  3322.         itemData.dataPtr = itemPtr->dataPtr;
  3323.         itemData.font = itemPtr->font;
  3324.         itemData.extra = itemPtr->extra;
  3325.         itemData.openSpace = itemPtr->openSpace;
  3326.         itemData.tabStops = itemPtr->tabStops;
  3327.         itemData.numRows = itemPtr->numRows;
  3328.         itemData.numCols = itemPtr->numCols;
  3329.         itemData.minLines = itemPtr->minLines;
  3330.         itemData.minHeight = itemPtr->minHeight;
  3331.         itemData.colFmt = itemPtr->colFmt;
  3332.         SetTableCharFormat (itemData.colFmt, itemData.numCols);
  3333.         if (itemData.prtProc != NULL) {
  3334.           FormatText (&ddata, 0, &itemData, FALSE, ddata.tabCount);
  3335.           SetTableCharFormat (itemData.colFmt, itemData.numCols);
  3336.           if (i > 0 && itemData.openSpace > 0) {
  3337.             fputc ('\n', f);
  3338.           }
  3339.           SaveTableItem (&itemData, f,
  3340.                          (Boolean) (unsigned int) itemData.tabStops,
  3341.                          ddata.tabCount);
  3342.           MemFree (itemData.text);
  3343.         }
  3344.       }
  3345.     }
  3346.   }
  3347. }
  3348.  
  3349. /*****************************************************************************
  3350. *
  3351. *   PrintDocument (d)
  3352. *       Reformats and sends a document to the printer
  3353. *
  3354. *****************************************************************************/
  3355.  
  3356. extern void PrintDocument (DoC d)
  3357.  
  3358. {
  3359. #if (defined(WIN_MAC) || defined (WIN_MSWIN))
  3360.   DocData   ddata;
  3361.   Boolean   goOn;
  3362.   Int2      i;
  3363.   Int2      item;
  3364.   ItemPtr   itemPtr;
  3365.   ItemData  itemData;
  3366.   Int2      line;
  3367.   Boolean   newPage;
  3368.   Int2      pixels;
  3369.   RecT      r;
  3370.   RecT      rct;
  3371.   FloatHi   scale;
  3372.   Int2      visBelow;
  3373.   WindoW    w;
  3374.  
  3375.   if (d != NULL) {
  3376.     GetPanelExtra ((PaneL) d, &ddata);
  3377.     ddata.isvirtual = FALSE;
  3378.     ddata.put = NULL;
  3379.     ddata.get = NULL;
  3380.     ddata.upd = NULL;
  3381.     if (ddata.numItems > 0) {
  3382.       ObjectRect (d, &rct);
  3383.       InsetRect (&rct, 4, 4);
  3384.       w = StartPrinting ();
  3385.       if (w != NULL) {
  3386.         for (i = 0; i < MAXFONTS; i++) {
  3387.           fontHeights [i].font = NULLFONT;
  3388.           fontHeights [i].height = 0;
  3389.         }
  3390.         goOn = TRUE;
  3391.         pixels = 0;
  3392.         item = 0;
  3393.         newPage = TRUE;
  3394.         while (item < ddata.numItems && goOn) {
  3395.           if (newPage) {
  3396.             goOn = StartPage ();
  3397.             newPage = FALSE;
  3398.             PrintingRect (&r);
  3399.           }
  3400.           if (goOn) {
  3401.             itemPtr = GetItemPtr (&ddata, item);
  3402.             if (itemPtr != NULL) {
  3403.               itemData.text = NULL;
  3404.               itemData.prtProc = itemPtr->prtProc;
  3405.               itemData.dataPtr = itemPtr->dataPtr;
  3406.               itemData.font = itemPtr->font;
  3407.               itemData.extra = itemPtr->extra;
  3408.               itemData.openSpace = itemPtr->openSpace;
  3409.               itemData.keepWithNext = itemPtr->keepWithNext;
  3410.               itemData.keepTogether = itemPtr->keepTogether;
  3411.               itemData.newPage = itemPtr->newPage;
  3412.               itemData.tabStops = itemPtr->tabStops;
  3413.               itemData.numRows = itemPtr->numRows;
  3414.               itemData.numCols = itemPtr->numCols;
  3415.               itemData.minLines = itemPtr->minLines;
  3416.               itemData.minHeight = itemPtr->minHeight;
  3417.               itemData.colFmt = (ColXPtr) MemNew (itemData.numCols * sizeof (ColXData));
  3418.               if (itemData.colFmt != NULL) {
  3419.                 MemCopy (itemData.colFmt, itemPtr->colFmt,
  3420.                          itemData.numCols * sizeof (ColXData));
  3421.                 for (i = 0; i < itemData.numCols; i++) {
  3422.                   if (itemData.colFmt [i].zeroWidth) {
  3423.                     itemData.colFmt [i].pixWidth = 0;
  3424.                   }
  3425.                 }
  3426.               }
  3427.               UpdateItemHeights (&itemData);
  3428.               scale = (FloatHi) (r.right - r.left) / (FloatHi) (rct.right - rct.left);
  3429.               for (i = 0; i < itemData.numCols; i++) {
  3430.                 itemData.colFmt [i].pixWidth = (Int2) (scale *
  3431.                                                (FloatHi) itemData.colFmt [i].pixWidth);
  3432.               }
  3433.               SetTablePixFormat (itemData.colFmt, r.left, itemData.numCols);
  3434.               if (itemData.prtProc != NULL) {
  3435.                 FormatText (&ddata, 0, &itemData, TRUE, ddata.tabCount);
  3436.                 SetTablePixFormat (itemData.colFmt, r.left, itemData.numCols);
  3437.                 if (pixels != 0) {
  3438.                   r.top += itemData.leadHeight;
  3439.                 }
  3440.                 visBelow = (r.bottom - r.top) / itemData.lineHeight;
  3441.                 if ((itemData.keepTogether && visBelow < itemData.numRows) ||
  3442.                     itemData.newPage) {
  3443.                   goOn = EndPage ();
  3444.                   if (goOn) {
  3445.                     goOn = StartPage ();
  3446.                   }
  3447.                   newPage = FALSE;
  3448.                   PrintingRect (&r);
  3449.                   visBelow = (r.bottom - r.top) / itemData.lineHeight;
  3450.                 }
  3451.                 line = 0;
  3452.                 while (visBelow + line < itemData.numRows && goOn) {
  3453.                   pixels = DrawTableItem (d, &itemData, &r, item, line, NULL,
  3454.                                           NULL, NULL, TRUE, ddata.tabCount);
  3455.                   r.top += pixels;
  3456.                   line += visBelow;
  3457.                   goOn = EndPage ();
  3458.                   if (goOn) {
  3459.                     StartPage ();
  3460.                   }
  3461.                   newPage = FALSE;
  3462.                   PrintingRect (&r);
  3463.                   visBelow = (r.bottom - r.top) / itemData.lineHeight;
  3464.                 }
  3465.                 if (visBelow > 0 && goOn) {
  3466.                   pixels = DrawTableItem (d, &itemData, &r, item, line, NULL,
  3467.                                           NULL, NULL, TRUE, ddata.tabCount);
  3468.                   r.top += pixels;
  3469.                 }
  3470.               }
  3471.               MemFree (itemData.text);
  3472.               MemFree (itemData.colFmt);
  3473.             }
  3474.           }
  3475.           item++;
  3476.           if (r.top >= r.bottom) {
  3477.             goOn = EndPage ();
  3478.             newPage = TRUE;
  3479.           }
  3480.         }
  3481.         if ((! newPage) && goOn) {
  3482.           goOn = EndPage ();
  3483.         }
  3484.         EndPrinting (w);
  3485.         for (i = 0; i < MAXFONTS; i++) {
  3486.           fontHeights [i].font = NULLFONT;
  3487.           fontHeights [i].height = 0;
  3488.         }
  3489.       }
  3490.     }
  3491.   }
  3492. #endif
  3493. }
  3494.  
  3495. /*****************************************************************************
  3496. *
  3497. *   displayTable
  3498. *       Default column table for file display functions
  3499. *
  3500. *****************************************************************************/
  3501.  
  3502. static ColData displayTable = {0, 0, 80, 0, NULLFONT, 'l',
  3503.                                TRUE, FALSE, FALSE, FALSE, TRUE};
  3504.  
  3505. /*****************************************************************************
  3506. *
  3507. *   GetChar (fp)
  3508. *       Gets a single character from a file, returning '\0' on end of file
  3509. *
  3510. *****************************************************************************/
  3511.  
  3512. static Char GetChar (FILE *fp)
  3513.  
  3514. {
  3515. #if (defined(OS_DOS) || defined (OS_NT))
  3516.   Int2  actual;
  3517.   Char  buf [32];
  3518.   Char  ch;
  3519.  
  3520.   ch = '\0';
  3521.   actual = (Int2) FileRead (buf, 1, 1, fp);
  3522.   if (actual > 0) {
  3523.     ch = buf [0];
  3524.   }
  3525.   return ch;
  3526. #else
  3527.   int  ch;
  3528.  
  3529.   ch = fgetc (fp);
  3530.   if (ch == EOF) {
  3531.     ch = '\0';
  3532.   }
  3533.   return (Char) ch;
  3534. #endif
  3535. }
  3536.  
  3537. /*****************************************************************************
  3538. *
  3539. *   DisplayFancy (d, file, parFmt, colFmt, font, tabStops)
  3540. *       Uses a document to display a file, allowing paragraph and column
  3541. *       formatting to be specified
  3542. *
  3543. *****************************************************************************/
  3544.  
  3545. extern void DisplayFancy (DoC d, CharPtr file, ParPtr parFmt,
  3546.                           ColPtr colFmt, FonT font, Int2 tabStops)
  3547.  
  3548. {
  3549.   Int2     actual;
  3550.   Char     ch;
  3551.   Int2     cnt;
  3552.   Int4     cntr;
  3553.   DocData  ddata;
  3554.   FILE     *fp;
  3555.   Int2     leftOver;
  3556.   ParData  para;
  3557.   RecT     r;
  3558.   WindoW   tempPort;
  3559.   CharPtr  text;
  3560.   CharPtr  txt;
  3561. #ifdef COMP_MPW
  3562.   CharPtr  p;
  3563. #endif
  3564. #if (defined(OS_DOS) || defined (OS_NT))
  3565.   CharPtr  p;
  3566.   CharPtr  q;
  3567. #endif
  3568.  
  3569.   if (d != NULL && file != NULL && file [0] != '\0') {
  3570.     GetPanelExtra ((PaneL) d, &ddata);
  3571.     ddata.tabCount = tabStops;
  3572.     SetPanelExtra ((PaneL) d, &ddata);
  3573.     if (parFmt == NULL) {
  3574.       parFmt = ¶
  3575.     }
  3576.     if (colFmt == NULL) {
  3577.       colFmt = &displayTable;
  3578.     }
  3579.     Reset (d);
  3580.     tempPort = SavePort (d);
  3581.     ObjectRect (d, &r);
  3582.     InsetRect (&r, 4, 4);
  3583.     displayTable.pixWidth = r.right - r.left;
  3584.     if (font == NULL) {
  3585.       font = systemFont;
  3586.     }
  3587.     text = (CharPtr) MemNew (16000);
  3588.     if (text != NULL) {
  3589.       fp = FileOpen (file, "r");
  3590.       if (fp != NULL) {
  3591.         leftOver = 0;
  3592.         cntr = FileLength (file);
  3593.         cnt = (Int2) MIN (cntr, 15000L);
  3594.         para.openSpace = FALSE;
  3595.         para.keepWithNext = FALSE;
  3596.         para.keepTogether = FALSE;
  3597.         para.newPage = FALSE;
  3598.         para.tabStops = TRUE;
  3599.         para.minLines = 0;
  3600.         para.minHeight = 0;
  3601.         while (cnt > 0 && cntr > 0) {
  3602.           txt = text + leftOver;
  3603.           actual = (Int2) FileRead (txt, 1, cnt, fp);
  3604.           if (actual > 0) {
  3605.             cnt = actual;
  3606.             txt [cnt] = '\0';
  3607.             ch = GetChar (fp);
  3608.             while (ch != '\0' && ch != '\n' && cnt < 15900) {
  3609.               txt [cnt] = ch;
  3610.               cnt++;
  3611.               ch = GetChar (fp);
  3612.             }
  3613.             while ((ch == '\n' || ch == '\r') && cnt < 15900) {
  3614.               txt [cnt] = ch;
  3615.               cnt++;
  3616.               ch = GetChar (fp);
  3617.             }
  3618.             txt [cnt] = '\0';
  3619. #if (defined(OS_DOS) || defined (OS_NT))
  3620.             p = text;
  3621.             q = text;
  3622.             while (*p) {
  3623.               if (*p == '\r') {
  3624.                 p++;
  3625.               } else {
  3626.                 *q = *p;
  3627.                 p++;
  3628.                 q++;
  3629.               }
  3630.             }
  3631.             *q = '\0';
  3632. #endif
  3633. #ifdef COMP_MPW
  3634.             p = text;
  3635.             while (*p) {
  3636.               if (*p == '\r') {
  3637.                 *p = '\n';
  3638.               }
  3639.               p++;
  3640.             }
  3641. #endif
  3642.             AppendText (d, text, parFmt, colFmt, font);
  3643.             leftOver = 1;
  3644.             text [0] = ch;
  3645.             cntr -= cnt;
  3646.             cnt = (Int2) MIN (cntr, 15000L);
  3647.           } else {
  3648.             cnt = 0;
  3649.             cntr = 0;
  3650.           }
  3651.         }
  3652.         FileClose (fp);
  3653.       }
  3654.       text = (CharPtr) MemFree (text);
  3655.     }
  3656.     if (Enabled (d) && AllParentsEnabled (d) &&
  3657.         Visible (d) && AllParentsVisible (d)) {
  3658.       ObjectRect (d, &r);
  3659.       InsetRect (&r, 3, 3);
  3660.       Select (d);
  3661.       InvalRect (&r);
  3662.     }
  3663.     if (! ddata.autoAdjust) {
  3664.       AdjustDocScroll (d);
  3665.     }
  3666.     RestorePort (tempPort);
  3667.   }
  3668. }
  3669.  
  3670. /*****************************************************************************
  3671. *
  3672. *   DisplayFile (d, file, font)
  3673. *       Simple function to display a file in a document
  3674. *
  3675. *****************************************************************************/
  3676.  
  3677. extern void DisplayFile (DoC d, CharPtr file, FonT font)
  3678.  
  3679. {
  3680.   DisplayFancy (d, file, NULL, NULL, font, 4);
  3681. }
  3682.