NCBI C Toolkit Cross Reference

C/vibrant/document.c


  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: 6.23 $
 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 * ==========================================================================
 42 */
 43 
 44 #include <vibrant.h>
 45 #include <document.h>
 46 #include <ncbilang.h>
 47 
 48 /*****************************************************************************
 49 *
 50 *   SYMBOL DEFINES
 51 *
 52 *****************************************************************************/
 53 
 54 #define JUST_LEFT   0
 55 #define JUST_CENTER 1
 56 #define JUST_RIGHT  2
 57 
 58 #define MAXLISTS  256
 59 #define LISTSIZE  256
 60 #define MAXFONTS   32
 61 
 62 /*****************************************************************************
 63 *
 64 *   TYPE DEFINES
 65 *
 66 *****************************************************************************/
 67 
 68 typedef struct colxdata {
 69   FonT          font;
 70   Int2          position;
 71   Int2          pixWidth;
 72   Int2          pixInset;
 73   Int2          charWidth;
 74   Int2          charInset;
 75   unsigned int  just      : 2;
 76   unsigned int  zeroWidth : 1;
 77   unsigned int  wrap      : 1;
 78   unsigned int  bar       : 1;
 79   unsigned int  underline : 1;
 80   unsigned int  left      : 1;
 81   unsigned int  last      : 1;
 82 } ColXData, PNTR ColXPtr;
 83 
 84 typedef struct itemdata {
 85   DocPrntProc   prtProc;
 86   Pointer       dataPtr;
 87   CharPtr       text;
 88   CharPtr       cached;
 89   FonT          font;
 90   ColXPtr       colFmt;
 91   VoidPtr       extra;
 92   Int4          startsAt;
 93   Int2          numRows;
 94   Int2          numCols;
 95   Int2          lineHeight;
 96   Int2          leadHeight;
 97   Int2          minLines;
 98   Int2          minHeight;
 99   unsigned int  openSpace    : 1;
100   unsigned int  keepWithNext : 1;
101   unsigned int  keepTogether : 1;
102   unsigned int  newPage      : 1;
103   unsigned int  tabStops     : 1;
104   unsigned int  docOwnsData  : 1;
105   unsigned int  notCached    : 1;
106   unsigned int  neverCached  : 1;
107 } ItemData, PNTR ItemPtr;
108 
109 typedef struct listdata {
110   ItemData  items [LISTSIZE];
111 } ListData, PNTR ListDPtr;
112 
113 typedef struct masterdata {
114   ListDPtr  list [MAXLISTS];
115 } MasterData, PNTR MasterPtr;
116 
117 typedef struct docdata {
118   DoC           doc;
119   MasterPtr     master;
120   DocDrawProc   draw;
121   DocCellProc   drawcell;
122   DocPanProc    pan;
123   DocShadeProc  gray;
124   DocShadeProc  invert;
125   DocShadeProc  color;
126   DocPutProc    put;
127   DocGetProc    get;
128   DocUpdProc    upd;
129   VoidPtr       data;
130   DocFreeProc   cleanup;
131   ValNodePtr    colFmts;
132   Int2          numItems;
133   Int4          numLines;
134   Int4          barmax;
135   Int2          pgUp;
136   Int2          pgDn;
137   Int2          tabCount;
138   Boolean       autoAdjust;
139   ParPtr        defaultParFmt;
140   ColPtr        defaultColFmt;
141   FonT          defaultFont;
142   Int2          firstHighlightItem;
143   Int2          lastHighlightItem;
144   Boolean       useRowsNotItems;
145   DocNotfyProc  notify;
146 } DocData, PNTR DocDataPtr;
147 
148 /*****************************************************************************
149 *
150 *   justToChar
151 *       Converts justification parameter to character code
152 *
153 *****************************************************************************/
154 
155 static Char  justToChar [4] = {'l', 'c', 'r', 'l'};
156 
157 /*****************************************************************************
158 *
159 *   fontHeights
160 *       Cached list of fonts and font pixel heights
161 *
162 *****************************************************************************/
163 
164 static struct fontheights {
165   FonT  font;
166   Int2  height;
167 } fontHeights [MAXFONTS];
168 
169 /*****************************************************************************
170 *
171 *   GetItemPtr (ddatptr, item)
172 *       Returns an item pointer given an item number
173 *
174 *****************************************************************************/
175 
176 static ItemPtr GetItemPtr (DocDataPtr ddatptr, Int2 item)
177 
178 {
179   Int2       index;
180   Int2       list;
181   ItemPtr    itemPtr;
182   ListDPtr   listPtr;
183   MasterPtr  masterPtr;
184 
185   itemPtr = NULL;
186   if (ddatptr != NULL && ddatptr->master != NULL && item < ddatptr->numItems) {
187     list = (item / LISTSIZE);
188     if (list < MAXLISTS) {
189       masterPtr = ddatptr->master;
190       listPtr = masterPtr->list [list];
191       if (listPtr != NULL) {
192         index = (item % LISTSIZE);
193         itemPtr = &(listPtr->items [index]);
194       }
195     }
196   }
197   return itemPtr;
198 }
199 
200 /*****************************************************************************
201 *
202 *   GetItemNum (ddatptr, desired)
203 *       Returns the number of the item containing the desired line
204 *
205 *****************************************************************************/
206 
207 static Int2 GetItemNum (DocDataPtr ddatptr, Int4 desired)
208 
209 {
210   Boolean  goOn;
211   ItemPtr  itemPtr;
212   Int4     left;
213   Int4     mid;
214   Int4     right;
215 
216   mid = 1;
217   if (ddatptr != NULL) {
218     left = 1;
219     right = ddatptr->numItems;
220     goOn = TRUE;
221     while (left <= right && goOn) {
222       mid = (left + right) / 2;
223       itemPtr = GetItemPtr (ddatptr, mid - 1);
224       if (itemPtr != NULL) {
225         if (desired < itemPtr->startsAt + itemPtr->numRows) {
226           right = mid - 1;
227         }
228         if (desired >= itemPtr->startsAt) {
229           left = mid + 1;
230         }
231       } else {
232         goOn = FALSE;
233         mid = 1;
234       }
235     }
236   }
237   return mid - 1;
238 }
239 
240 /*****************************************************************************
241 *
242 *   GetNextBlock (title, maxwid, byPixels, wordWrap, tabStops, tabCount)
243 *       Returns the number of characters in the next block, including
244 *       trailing spaces (which are trimmed back later)
245 *
246 *****************************************************************************/
247 
248 static Int2 GetNextBlock (CharPtr title, Int2 maxwid, Boolean byPixels,
249                           Boolean wordWrap, Boolean tabStops, Int2 tabCount)
250 
251 {
252   Char     ch;
253   Int2     i;
254   Boolean  isjapanese;
255   Int2     j;
256   Int2     wid;
257 
258   isjapanese = IsJapanese ();
259   if (isjapanese) {
260   i = 0;
261   j = 0;
262   wid = 0;
263   if (title != NULL && maxwid > 0) {
264     ch = title [i];
265     while (ch != '\0' && ch != '\n' && ch != '\r' &&
266            (ch != '\t' || tabStops) && wid <= maxwid) {
267       if (wordWrap) {
268         if (ch == '\t' && tabStops) {
269           if (byPixels) {
270             wid += CharWidth (' ') * tabCount;
271           } else {
272             wid += tabCount;
273           }
274         } else {
275           if (byPixels) {
276             wid += TextWidth(title + i, Nlm_LetterByte(title + i));
277           } else {
278             wid += Nlm_LetterByte(title + i);
279           }
280         }
281       }
282       i += Nlm_LetterByte(title + i);
283       ch = title [i];
284     }
285     j = i;
286 /* sorry, 1 or 2 byte letters only. but isn't it enough ? */
287 #define BackIsMBLetter(str, i)  ((i > 1) && (IsMBLetter(title + i - 2)))
288 #define BackStep(str, i)        (BackIsMBLetter(str, i) ? 2 : 1)
289     if (wid > maxwid && wordWrap) {
290       j -= BackStep(title, j);
291       if (byPixels) {
292         while (TextWidth (title, i) > maxwid) {
293           i -= BackStep(title, i);
294         }
295       } else {
296         while (i > maxwid) {
297           i -= BackStep(title, i);
298         }
299       }
300           while (i > 0 && title[i - 1] != ' ' && title [i - 1] != '-' && 
301                                                                                 !(BackIsMBLetter(title, i))) {
302         /* at least in Japanese, almost all of multibyte letters are
303            good as a word wrap point. */
304         i -= BackStep(title, i);
305           }
306       while (title [i] == ' ') {
307         i++;
308       }
309     }
310   }
311   } else {
312   i = 0;
313   j = 0;
314   wid = 0;
315   if (title != NULL && maxwid > 0) {
316     ch = title [i];
317     while (ch != '\0' && ch != '\n' && ch != '\r' &&
318            (ch != '\t' || tabStops) && wid <= maxwid) {
319       if (wordWrap) {
320         if (ch == '\t' && tabStops) {
321           if (byPixels) {
322             wid += CharWidth (' ') * tabCount;
323           } else {
324             wid += tabCount;
325           }
326         } else {
327           if (byPixels) {
328             wid += CharWidth (ch);
329           } else {
330             wid++;
331           }
332         }
333       }
334       i++;
335       ch = title [i];
336     }
337     j = i;
338     if (wid > maxwid && wordWrap) {
339       j--;
340       if (byPixels) {
341         while (TextWidth (title, i) > maxwid) {
342           i--;
343         }
344       } else {
345         while (i > maxwid) {
346           i--;
347         }
348       }
349       while (i > 0 && title [i - 1] != ' ' && title [i - 1] != '-') {
350         i--;
351       }
352       while (title [i] == ' ') {
353         i++;
354       }
355     }
356   }
357   }
358   if (i > 0 && i < j) {
359     return i;
360   } else if (j > 0) {
361     return j;
362   } else {
363     return 0;
364   }
365 }
366 
367 /*****************************************************************************
368 *
369 *   CELL STRUCTURE DEFINITIONS
370 *
371 *****************************************************************************/
372 
373 #define CELLCHUNK 128
374 
375 typedef struct celldata {
376   Uint4  start;
377   Int2   count;
378 } CellData, PNTR CellPtr;
379 
380 typedef struct parsedata {
381   Int4     numCells;
382   CellPtr  cellPtr;
383 } ParseData, PNTR ParsePtr;
384 
385 /*****************************************************************************
386 *
387 *   RecordCell (itemPtr, parsePtr, start, len, row, col)
388 *       Records the character position and length for a given cell
389 *
390 *****************************************************************************/
391 
392 static void RecordCell (ItemPtr itemPtr, ParsePtr parsePtr,
393                         Uint4 start, Int2 len, Int2 row, Int2 col)
394 
395 {
396   Int4     cell;
397   CellPtr  cellPtr;
398   Int4     newCells;
399   Int4     numCells;
400 
401   if (itemPtr != NULL && parsePtr != NULL && col < itemPtr->numCols) {
402     numCells = parsePtr->numCells;
403     cellPtr = parsePtr->cellPtr;
404     cell = (Int4) ((Int4) row * (Int4) (itemPtr->numCols) + (Int4) col);
405     if (cell >= (Int4) numCells) {
406       newCells = (cell / CELLCHUNK + 1) * CELLCHUNK;
407       if (cellPtr != NULL) {
408         cellPtr = (CellPtr) MemMore (cellPtr, sizeof (CellData) * newCells);
409         if (cellPtr != NULL) {
410           while (numCells < newCells) {
411             cellPtr [numCells].start = 0;
412             cellPtr [numCells].count = 0;
413             numCells++;
414           }
415         }
416       } else {
417         cellPtr = (CellPtr) MemNew (sizeof (CellData) * newCells);
418       }
419       parsePtr->cellPtr = cellPtr;
420       parsePtr->numCells = newCells;
421     }
422     if (cellPtr != NULL) {
423       cellPtr [cell].start = start;
424       cellPtr [cell].count = len;
425     }
426   }
427 }
428 
429 /*****************************************************************************
430 *
431 *   ParseText (itemPtr, parsePtr, text, byPixels, tabCount)
432 *       Parses text that contains \t, \r and \n characters into a list of
433 *       cells organized by row and column
434 *
435 *****************************************************************************/
436 
437 static void ParseText (ItemPtr itemPtr, ParsePtr parsePtr,
438                        CharPtr text, Boolean byPixels, Int2 tabCount)
439 
440 {
441   Int2     blklen;
442   Char     ch;
443   Int2     col;
444   ColXPtr  colFmt;
445   FonT     curFont;
446   FonT     fnt;
447   Int2     inset;
448   Int2     insetLeft;
449   Int2     insetRight;
450   Char     just;
451   Int2     len;
452   Int2     maxwid;
453   Int2     numCols;
454   Int2     numRows;
455   Int2     returnRow;
456   Int2     row;
457   Uint4    start;
458   Int2     tabRow;
459   Boolean  tabStops;
460   Int2     width;
461   Boolean  wrap;
462 
463   if (itemPtr != NULL && parsePtr != NULL && text != NULL && *text != '\0') {
464     curFont = NULL;
465     colFmt = itemPtr->colFmt;
466     if (colFmt != NULL) {
467       fnt = itemPtr->font;
468       if (byPixels) {
469         if (fnt != NULL) {
470           SelectFont (fnt);
471           curFont = fnt;
472         } else {
473           SelectFont (systemFont);
474           curFont = systemFont;
475         }
476       }
477       start = 0;
478       row = 0;
479       tabRow = 0;
480       returnRow = 1;
481       col = 0;
482       tabStops = itemPtr->tabStops;
483       numRows = 0;
484       numCols = itemPtr->numCols;
485       while (text [start] != '\0') {
486         len = 0;
487         wrap = FALSE;
488         ch = text [start];
489         if (ch != '\0' && ch != '\n' && ch != '\r' && (ch != '\t' || tabStops)) {
490           maxwid = INT2_MAX;
491           if (col < numCols) {
492             if (byPixels) {
493               width = colFmt [col].pixWidth;
494               inset = colFmt [col].pixInset;
495             } else {
496               width = colFmt [col].charWidth;
497               inset = colFmt [col].charInset;
498             }
499             just = justToChar [colFmt [col].just];
500             wrap = colFmt [col].wrap;
501             fnt = colFmt [col].font;
502           } else {
503             width = 0;
504             inset = 0;
505             just = 'l';
506             wrap = FALSE;
507             fnt = NULL;
508           }
509           if (just == 'c') {
510             insetLeft = inset;
511             insetRight = inset;
512           } else if (just == 'l') {
513             insetLeft = inset;
514             insetRight = 0;
515           } else if (just == 'r') {
516             insetLeft = 0;
517             insetRight = inset;
518           } else {
519             insetLeft = 0;
520             insetRight = 0;
521           }
522           if (byPixels) {
523             if (col < numCols && wrap && width > 0 &&
524                 width >= 2 + insetLeft + insetRight) {
525               maxwid = width - 2 - insetLeft - insetRight;
526             }
527           } else {
528             if (col < numCols && wrap && width > 0 &&
529                 width >= insetLeft + insetRight) {
530               maxwid = width - insetLeft - insetRight;
531             }
532           }
533           if (byPixels) {
534             if (fnt != NULL) {
535               if (fnt != curFont) {
536                 SelectFont (fnt);
537                 curFont = fnt;
538               }
539             } else {
540               fnt = itemPtr->font;
541               if (fnt != NULL) {
542                 if (fnt != curFont) {
543                   SelectFont (fnt);
544                   curFont = fnt;
545                 }
546               }
547             }
548           }
549           blklen = GetNextBlock (text + start, maxwid, byPixels,
550                                  wrap, tabStops, tabCount);
551           len = blklen;
552           if (len > 0) {
553             if (text [start + len] != '\0') {
554               while (len > 0 && text [start + len - 1] == ' ') {
555                 len--;
556               }
557               if (len == 0) {
558                 len = blklen;
559               }
560             }
561             RecordCell (itemPtr, parsePtr, start, len, row, col);
562             if (len > 0 && col < numCols && colFmt [col].zeroWidth) {
563               if (byPixels) {
564                 colFmt [col].pixWidth = TextWidth (text + start, len) +
565                                         CharWidth (' ') + 2;
566               } else {
567                 colFmt [col].charWidth = len + 1;
568               }
569             }
570             start += blklen;
571           } else {
572             if (byPixels) {
573               while (TextWidth (text + start, len) <= maxwid) {
574                 len++;
575               }
576             } else {
577               while (len <= maxwid) {
578                 len++;
579               }
580             }
581             len--;
582             if (len > 0) {
583               RecordCell (itemPtr, parsePtr, start, len, row, col);
584             }
585             ch = text [start];
586             while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '\t') {
587               start++;
588               ch = text [start];
589             }
590           }
591         }
592         ch = text [start];
593         if (ch == '\n') {
594           start++;
595           row = returnRow;
596           tabRow = row;
597           returnRow++;
598           col = 0;
599         } else if (ch == '\r') {
600           start++;
601           row++;
602           returnRow = MAX (returnRow, row + 1);
603         } else if (ch == '\t') {
604           start++;
605           row = tabRow;
606           col++;
607           if (text [start] == '\0') {
608             row = returnRow;
609           }
610         } else if (ch != '\0' && wrap) {
611           if (len == 0) {
612             start++;
613           }
614           row++;
615           returnRow = MAX (returnRow, row + 1);
616         } else if (ch != '\0') {
617           start++;
618         } else if (text [start - 1] != '\n' && text [start - 1] != '\r') {
619           row = returnRow;
620         }
621         numRows = MAX (numRows, row);
622       }
623       itemPtr->numRows = MAX (numRows, itemPtr->minLines);
624     }
625     SelectFont (systemFont);
626   } else if (itemPtr != NULL) {
627     itemPtr->numRows = 0;
628   }
629 }
630 
631 /*****************************************************************************
632 *
633 *   RearrangeText (itemPtr, parsePtr, text)
634 *       Reconstructs text in row and column order so that the list of cells
635 *       does not need to persist
636 *
637 *****************************************************************************/
638 
639 static void RearrangeText (ItemPtr itemPtr, ParsePtr parsePtr, CharPtr text)
640 
641 {
642   Int4     cell;
643   CellPtr  cellPtr;
644   Int2     col;
645   ColXPtr  colFmt;
646   CharPtr  dst;
647   Int4     len;
648   Int2     minLines;
649   Int4     numCells;
650   Int2     numCols;
651   Int2     numRows;
652   Int2     row;
653   CharPtr  src;
654   CharPtr  str;
655 
656   if (itemPtr != NULL && parsePtr != NULL && text != NULL && *text != '\0') {
657     colFmt = itemPtr->colFmt;
658     if (colFmt != NULL) {
659       numRows = itemPtr->numRows;
660       numCols = itemPtr->numCols;
661       minLines = itemPtr->minLines;
662       if (parsePtr->numCells > 0 && parsePtr->cellPtr != NULL) {
663         cellPtr = parsePtr->cellPtr;
664         numCells = parsePtr->numCells;
665         len = (Int4) (numRows * numCols);
666         for (row = 0; row < numRows; row++) {
667           for (col = 0; col < numCols; col++) {
668             cell = (Int4) ((Int4) row * (Int4) numCols + (Int4) col);
669             if (cell < (Int4) numCells) {
670               len += (Int4) (cellPtr [cell].count);
671             }
672           }
673         }
674         len += (Int4) minLines + (Int4) 4;
675         str = NULL;
676         if ((size_t)len < SIZE_MAX) {
677           str = (CharPtr) MemNew ((size_t) (Uint4) len);
678           if (str != NULL) {
679             dst = str;
680             for (row = 0; row < numRows; row++) {
681               for (col = 0; col < numCols; col++) {
682                 cell = (Int4) ((Int4) row * (Int4) numCols + (Int4) col);
683                 if (cell < numCells) {
684                   if (col > 0) {
685                     *dst = '\t';
686                     dst++;
687                   }
688                   src = text + cellPtr [cell].start;
689                   len = (Int4) (cellPtr [cell].count);
690                   while (len > 0) {
691                     *dst = *src;
692                     dst++;
693                     src++;
694                     len--;
695                   }
696                 }
697               }
698               *dst = '\n';
699               dst++;
700             }
701             while (row < minLines) {
702               *dst = '\n';
703               dst++;
704               row++;
705             }
706             *dst = '\0';
707           }
708         }
709         itemPtr->text = str;
710       }
711     }
712   }
713 }
714 
715 /*****************************************************************************
716 *
717 *   FormatText (ddatptr, item, itemPtr, byPixels, tabCount)
718 *       Calls the print function for the item, then parses and rearranges
719 *       the text so that it can be displayed, saved, or printed
720 *
721 *****************************************************************************/
722 
723 static void FormatText (DocDataPtr ddatptr, Int2 item, ItemPtr itemPtr,
724                         Boolean byPixels, Int2 tabCount)
725 
726 {
727   Boolean    needToParse;
728   ParseData  parseData;
729   CharPtr    text;
730 
731   if (itemPtr != NULL && itemPtr->text == NULL && itemPtr->prtProc != NULL) {
732     needToParse = TRUE;
733     text = NULL;
734     if (ddatptr != NULL && ddatptr->get != NULL) {
735       text = ddatptr->get (ddatptr->doc, item);
736       if (text != NULL) {
737         needToParse = FALSE;
738       } else {
739         text = itemPtr->prtProc (ddatptr->doc, item, itemPtr->dataPtr);
740       }
741     } else if (ddatptr != NULL) {
742       text = itemPtr->prtProc (ddatptr->doc, item, itemPtr->dataPtr);
743     }
744     if (needToParse && text != NULL && *text != '\0') {
745       parseData.numCells = 0;
746       parseData.cellPtr = NULL;
747       ParseText (itemPtr, &parseData, text, byPixels, tabCount);
748       RearrangeText (itemPtr, &parseData, text);
749       itemPtr->notCached = FALSE;
750       itemPtr->neverCached = FALSE;
751       MemFree (text);
752       MemFree (parseData.cellPtr);
753     } else {
754       itemPtr->text = text;
755     }
756     text = itemPtr->text;
757     if (text == NULL || *text == '\0') {
758       MemFree (itemPtr->text);
759       itemPtr->text = StringSave (" \n");
760       itemPtr->numRows = 1;
761       itemPtr->notCached = FALSE;
762       itemPtr->neverCached = FALSE;
763       needToParse = TRUE;
764     }
765     if (needToParse && ddatptr != NULL && ddatptr->put != NULL) {
766       ddatptr->put (ddatptr->doc, item, itemPtr->text);
767     }
768   }
769 }
770 
771 /*****************************************************************************
772 *
773 *   GetStartsAt (ddatptr, item)
774 *       Returns the first line of the item
775 *
776 *****************************************************************************/
777 
778 static Int4 GetStartsAt (DocDataPtr ddatptr, Int2 item)
779 
780 {
781   Int4     startsAt;
782   ItemPtr  itemPtr;
783 
784   startsAt = 0;
785   if (ddatptr != NULL) {
786     itemPtr = GetItemPtr (ddatptr, item);
787     if (itemPtr != NULL) {
788       startsAt = itemPtr->startsAt;
789     }
790   }
791   return startsAt;
792 }
793 
794 /*****************************************************************************
795 *
796 *   GetLineHeight (ddatptr, item)
797 *       Returns the pixel height of the item
798 *
799 *****************************************************************************/
800 
801 static Int2 GetLineHeight (DocDataPtr ddatptr, Int2 item)
802 
803 {
804   ItemPtr  itemPtr;
805   Int2     lineHeight;
806 
807   lineHeight = 0;
808   if (ddatptr != NULL) {
809     itemPtr = GetItemPtr (ddatptr, item);
810     if (itemPtr != NULL) {
811       lineHeight = itemPtr->lineHeight;
812     }
813   }
814   return lineHeight;
815 }
816 
817 /*****************************************************************************
818 *
819 *   SetTablePixFormat (colFmt, left, numCols)
820 *       Uses pixel widths to calculate the positions of columns for drawing
821 *
822 *****************************************************************************/
823 
824 static void SetTablePixFormat (ColXPtr colFmt, Int2 left, Int2 numCols)
825 
826 {
827   Int2  i;
828 
829   if (colFmt != NULL) {
830     colFmt [0].position = left;
831     for (i = 1; i < numCols; i++) {
832       if (colFmt [i].left) {
833         colFmt [i].position = left;
834       } else {
835         colFmt [i].position = colFmt [i - 1].position + colFmt [i - 1].pixWidth;
836       }
837     }
838   }
839 }
840 
841 /*****************************************************************************
842 *
843 *   SetTableCharFormat (colFmt, numCols)
844 *       Uses character counts to calculate the positions of columns for saving
845 *
846 *****************************************************************************/
847 
848 static void SetTableCharFormat (ColXPtr colFmt, Int2 numCols)
849 
850 {
851   Int2  i;
852 
853   if (colFmt != NULL) {
854     colFmt [0].position = 0;
855     for (i = 1; i < numCols; i++) {
856       if (colFmt [i].left) {
857         colFmt [i].position = 0;
858       } else {
859         colFmt [i].position = colFmt [i - 1].position + colFmt [i - 1].charWidth;
860       }
861     }
862   }
863 }
864 
865 /*****************************************************************************
866 *
867 *   UpdateLineStarts (ddatptr, frst)
868 *       Recalculates the first lines as a running sum of the number of rows
869 *
870 *****************************************************************************/
871 
872 static Int4 UpdateLineStarts (DocDataPtr ddatptr, Int2 frst)
873 
874 {
875   Int2     i;
876   ItemPtr  itemPtr;
877   Int4     totalNumLines;
878 
879   totalNumLines = 0;
880   if (ddatptr != NULL) {
881     itemPtr = GetItemPtr (ddatptr, frst);
882     if (itemPtr != NULL) {
883       totalNumLines = itemPtr->startsAt;
884     }
885     for (i = frst; i < ddatptr->numItems; i++) {
886       itemPtr = GetItemPtr (ddatptr, i);
887       if (itemPtr != NULL) {
888         itemPtr->startsAt = totalNumLines;
889         totalNumLines += itemPtr->numRows;
890       }
891     }
892   }
893   return totalNumLines;
894 }
895 
896 /*****************************************************************************
897 *
898 *   CollectRange (item, lowest, highest)
899 *       Records the range of items that were manipulated for the purpose of
900 *       updating line starts or uncaching formatted text on items that are
901 *       not currently visible
902 *
903 *****************************************************************************/
904 
905 static void CollectRange (Int2 item, Int2Ptr lowest, Int2Ptr highest)
906 
907 {
908   if (lowest != NULL) {
909     *lowest = MIN (*lowest, item);
910   }
911   if (highest != NULL) {
912     *highest = MAX (*highest, item);
913   }
914 }
915 
916 /*****************************************************************************
917 *
918 *   CacheAndFormat (ddatptr, item, itemPtr, r, tabCount)
919 *       Formats text (for drawing) if the item text is not currently cached
920 *
921 *****************************************************************************/
922 
923 static void CacheAndFormat (DocDataPtr ddatptr, Int2 item, ItemPtr itemPtr,
924                             RectPtr r, Int2 tabCount)
925 
926 {
927   if (itemPtr != NULL && r != NULL && itemPtr->notCached) {
928     SetTablePixFormat (itemPtr->colFmt, r->left, itemPtr->numCols);
929     FormatText (ddatptr, item, itemPtr, TRUE, tabCount);
930   }
931 }
932 
933 /*****************************************************************************
934 *
935 *   CacheIfNever (ddatptr, item, itemPtr, r, tabCount)
936 *       Formats text (for obtaining the correct number of rows) if the item
937 *       text has never been cached
938 *
939 *****************************************************************************/
940 
941 static void CacheIfNever (DocDataPtr ddatptr, Int2 item, ItemPtr itemPtr,
942                           RectPtr r, Int2 tabCount)
943 
944 {
945   if (itemPtr != NULL && r != NULL && itemPtr->neverCached) {
946     SetTablePixFormat (itemPtr->colFmt, r->left, itemPtr->numCols);
947     FormatText (ddatptr, item, itemPtr, TRUE, tabCount);
948   }
949 }
950 
951 /*****************************************************************************
952 *
953 *   FreeCachedItem (ddatptr, item, lowest, highest)
954 *       Frees the formatted text string for an item that is not currently
955 *       visible
956 *
957 *****************************************************************************/
958 
959 static void FreeCachedItem (DocDataPtr ddatptr, Int2 item,
960                             Int2Ptr lowest, Int2Ptr highest)
961 
962 {
963   ItemPtr  itemPtr;
964 
965   if (ddatptr != NULL) {
966     itemPtr = GetItemPtr (ddatptr, item);
967     if (itemPtr != NULL) {
968       itemPtr->text = (CharPtr) MemFree (itemPtr->text);
969       itemPtr->notCached = TRUE;
970     }
971   }
972 }
973 
974 /*****************************************************************************
975 *
976 *   VisLinesAbove (ddatptr, r, item, line, lowest, highest)
977 *       Returns the number of lines visible on the screen if the given line
978 *       in the given item is the last line visible
979 *
980 *****************************************************************************/
981 
982 static Int2 VisLinesAbove (DocDataPtr ddatptr, RectPtr r, Int2 item,
983                            Int2 line, Int2Ptr lowest, Int2Ptr highest)
984 
985 {
986   ItemPtr  itemPtr;
987   Int2     pixels;
988   Int2     vis;
989 
990   vis = 0;
991   if (ddatptr != NULL && r != NULL && item < ddatptr->numItems) {
992     pixels = r->bottom - r->top;
993     while (pixels > 0 && item >= 0) {
994       itemPtr = GetItemPtr (ddatptr, item);
995       if (itemPtr != NULL) {
996         CollectRange (item, lowest, highest);
997         CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
998         if (line < 0) {
999           line = itemPtr->numRows - 1;
1000         }
1001         while (pixels > 0 && line >= 0 && line < itemPtr->numRows) {
1002           pixels -= itemPtr->lineHeight;
1003           if (pixels >= 0) {
1004             vis++;
1005           }
1006           line--;
1007         }
1008         pixels -= itemPtr->leadHeight;
1009       }
1010       item--;
1011     }
1012   }
1013   return vis;
1014 }
1015 
1016 /*****************************************************************************
1017 *
1018 *   VisLinesBelow (ddatptr, r, item, line, lowest, highest)
1019 *       Returns the number of lines visible on the screen if the given line
1020 *       in the given item is the first line visible
1021 *
1022 *****************************************************************************/
1023 
1024 static Int2 VisLinesBelow (DocDataPtr ddatptr, RectPtr r, Int2 item,
1025                            Int2 line, Int2Ptr lowest, Int2Ptr highest)
1026 
1027 {
1028   ItemPtr  itemPtr;
1029   Int2     pixels;
1030   Int2     vis;
1031 
1032   vis = 0;
1033   if (ddatptr != NULL && r != NULL && item < ddatptr->numItems && item >= 0) {
1034     pixels = r->bottom - r->top;
1035     while (pixels > 0 && item < ddatptr->numItems) {
1036       itemPtr = GetItemPtr (ddatptr, item);
1037       if (itemPtr != NULL) {
1038         CollectRange (item, lowest, highest);
1039         CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
1040         if (line  < 0) {
1041           line = 0;
1042           pixels -= itemPtr->leadHeight;
1043         }
1044         while (pixels > 0 && line >= 0 && line < itemPtr->numRows) {
1045           pixels -= itemPtr->lineHeight;
1046           if (pixels >= 0) {
1047             vis++;
1048           }
1049           line++;
1050         }
1051         line = -1;
1052       }
1053       item++;
1054     }
1055   }
1056   return vis;
1057 }
1058 
1059 /*****************************************************************************
1060 *
1061 *   PixelsBetween (ddatptr, r, firstLine, lastLine, lowest, highest)
1062 *       Returns the number of pixels between two lines
1063 *
1064 *****************************************************************************/
1065 
1066 static Int2 PixelsBetween (DocDataPtr ddatptr, RectPtr r, Int4 firstLine,
1067                            Int4 lastLine, Int2Ptr lowest, Int2Ptr highest)
1068 
1069 {
1070   Int2     count;
1071   Int2     item;
1072   ItemPtr  itemPtr;
1073   Int4     line;
1074   Int4     numLines;
1075   Int2     onItem;
1076   Int2     pixels;
1077 
1078   pixels = 0;
1079   if (ddatptr != NULL && r != NULL) {
1080     count = ABS (lastLine - firstLine);
1081     item = GetItemNum (ddatptr, MIN (firstLine, lastLine));
1082     itemPtr = GetItemPtr (ddatptr, item);
1083     onItem = item;
1084     if (itemPtr != NULL && item >= 0) {
1085       CollectRange (item, lowest, highest);
1086       CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
1087       line = MIN (firstLine, lastLine) - itemPtr->startsAt;
1088       while (count > 0 && item < ddatptr->numItems) {
1089         if (item != onItem) {
1090           itemPtr = GetItemPtr (ddatptr, item);
1091           onItem = item;
1092         }
1093         numLines = 0;
1094         if (itemPtr != NULL) {
1095           CollectRange (item, lowest, highest);
1096           CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
1097           numLines = itemPtr->numRows;
1098           while (count > 0 && line >= 0 && line < numLines) {
1099             pixels += itemPtr->lineHeight;
1100             line++;
1101             count--;
1102           }
1103         }
1104         item++;
1105         if (line >= numLines) {
1106           itemPtr = GetItemPtr (ddatptr, item);
1107           onItem = item;
1108           if (itemPtr != NULL) {
1109             CollectRange (item, lowest, highest);
1110             CacheIfNever (ddatptr, item + 1, itemPtr, r, ddatptr->tabCount);
1111             pixels += itemPtr->leadHeight;
1112           }
1113         }
1114         line = 0;
1115       }
1116       if (lastLine < firstLine) {
1117         pixels = -pixels;
1118       }
1119     }
1120   }
1121   return pixels;
1122 }
1123 
1124 /*****************************************************************************
1125 *
1126 *   DrawTableItem (d, ddatptr, itemPtr, r, item, frst, grayProc,
1127                    invertProc, colorProc, force, tabCount)
1128 *       Draws a given item on the screen, suppressing partial lines
1129 *
1130 *****************************************************************************/
1131 
1132 static Boolean is_old_win = FALSE;
1133 #ifdef OS_MSWIN
1134 static Boolean old_win_set = FALSE;
1135 #endif
1136 
1137 static Int2 DrawTableItem (DoC d, DocDataPtr ddatptr, ItemPtr itemPtr, RectPtr r,
1138                           Int2 item, Int2 frst, DocShadeProc grayProc,
1139                           DocShadeProc invertProc, DocShadeProc colorProc,
1140                           Boolean force, Int2 tabCount)
1141 
1142 {
1143   Int2     barBottom;
1144   Int2     barTop;
1145   Char     ch;
1146   Int2     col;
1147   Boolean  color;
1148   ColXPtr  colFmt;
1149   FonT     curFont;
1150   Uint4    currentColor;
1151   Boolean  drawBars;
1152   RecT     drw;
1153   FonT     fnt;
1154   Boolean  gray;
1155   Int2     insetLeft;
1156   Int2     insetRight;
1157   Boolean  invert;
1158   Char     just;
1159   Int2     lineHeight;
1160   Int2     num;
1161   CharPtr  ptr;
1162   RecT     rct;
1163   Int2     row;
1164   Int2     rsult;
1165   CharPtr  text;
1166   CharPtr  tmp;
1167 
1168 #ifdef OS_MSWIN
1169   if (! old_win_set) {
1170     text = GetOpSysString ();
1171     if (StringICmp (text, "MS WINDOWS 95/98/Me") == 0 ||
1172         StringICmp (text, "MS WINDOWS 3.1") == 0) {
1173       is_old_win = TRUE;
1174     }
1175     text = MemFree (text);
1176     old_win_set = TRUE;
1177   }
1178 #endif
1179 
1180   rsult = 0;
1181   if (d != NULL && ddatptr != NULL && itemPtr != NULL && r != NULL) {
1182     text = itemPtr->text;
1183     colFmt = itemPtr->colFmt;
1184     if (text != NULL && *text != '\0' && colFmt != NULL) {
1185       fnt = itemPtr->font;
1186       if (fnt != NULL) {
1187         curFont = fnt;
1188       } else {
1189         curFont = systemFont;
1190       }
1191       SelectFont (curFont);
1192       lineHeight = itemPtr->lineHeight;
1193       rct.top = r->top;
1194       rct.bottom = rct.top;
1195       row = 0;
1196       col = 0;
1197       ptr = text;
1198       ch = *ptr;
1199       currentColor = 0;
1200       if (colorProc != NULL && (! force)) {
1201         currentColor = GetColor ();
1202       }
1203       drawBars = FALSE;
1204       barTop = INT2_MAX;
1205       barBottom = INT2_MIN;
1206       while (ch != '\0') {
1207         if (ch == '\n') {
1208           rct.top = r->top + (row - frst) * lineHeight;
1209           rct.bottom = rct.top + lineHeight;
1210           InvertMode ();
1211           for (col = 0; col < itemPtr->numCols; col++) {
1212             rct.left = colFmt [col].position;
1213             rct.right = rct.left + colFmt [col].pixWidth;
1214             if (colFmt [col].bar) {
1215               drawBars = TRUE;
1216               barTop = MIN (barTop, rct.top);
1217               barBottom = MAX (barBottom, rct.bottom);
1218             }
1219             if (colFmt [col].underline) {
1220               MoveTo (rct.left, rct.bottom - 1);
1221               LineTo (rct.right, rct.bottom - 1);
1222             }
1223           }
1224           CopyMode ();
1225           col = 0;
1226           row++;
1227           ptr++;
1228         } else if (ch == '\t' && (! (itemPtr->tabStops))) {
1229           col++;
1230           ptr++;
1231           ch = *ptr;
1232           if (ch == '\t' && (! (itemPtr->tabStops)) &&
1233               row >= frst && col < itemPtr->numCols) {
1234             rct.top = r->top + (row - frst) * lineHeight;
1235             rct.bottom = rct.top + lineHeight;
1236             rct.left = colFmt [col].position;
1237             rct.right = rct.left + colFmt [col].pixWidth;
1238             LoadRect (&drw, MAX (rct.left, r->left), rct.top,
1239                       MIN (rct.right, r->right), rct.bottom);
1240             if (RectInRect (&drw, r) &&
1241                 (force || updateRgn == NULL || RectInRgn (&rct, updateRgn))) {
1242               invert = FALSE;
1243               if (invertProc != NULL && (! force)) {
1244                 invert = invertProc (d, item + 1, row + 1, col + 1);
1245               } else if (ddatptr->useRowsNotItems) {
1246                 invert = (Boolean) (ddatptr->firstHighlightItem <= row + 1 &&
1247                                     ddatptr->lastHighlightItem >= row + 1);
1248               } else {
1249                 invert = (Boolean) (ddatptr->firstHighlightItem <= item + 1 &&
1250                                     ddatptr->lastHighlightItem >= item + 1);
1251               }
1252               if (invert) {
1253                 InvertColors ();
1254                 EraseRect (&rct);
1255                 InvertColors ();
1256               }
1257             }
1258           }
1259         } else  {
1260           num = 0;
1261           while (ch != '\0' && (ch != '\t' || itemPtr->tabStops) && ch != '\n') {
1262             num++;
1263             ch = ptr [num];
1264           }
1265           if (row >= frst && col < itemPtr->numCols) {
1266             rct.top = r->top + (row - frst) * lineHeight;
1267             rct.bottom = rct.top + lineHeight;
1268             rct.left = colFmt [col].position;
1269             rct.right = rct.left + colFmt [col].pixWidth;
1270             LoadRect (&drw, MAX (rct.left, r->left), rct.top,
1271                       MIN (rct.right, r->right), rct.bottom);
1272             if (RectInRect (&drw, r) &&
1273                 (force || updateRgn == NULL || RectInRgn (&rct, updateRgn))) {
1274               just = justToChar [colFmt [col].just];
1275               if (just == 'c') {
1276                 insetLeft = colFmt [col].pixInset;
1277                 insetRight = colFmt [col].pixInset;
1278               } else if (just == 'l') {
1279                 insetLeft = colFmt [col].pixInset;
1280                 insetRight = 0;
1281               } else if (just == 'r') {
1282                 insetLeft = 0;
1283                 insetRight = colFmt [col].pixInset;
1284               } else {
1285                 insetLeft = 0;
1286                 insetRight = 0;
1287               }
1288               fnt = colFmt [col].font;
1289               if (fnt != NULL) {
1290                 if (fnt != curFont) {
1291                   curFont = fnt;
1292                   SelectFont (curFont);
1293                 }
1294               } else {
1295                 fnt = itemPtr->font;
1296                 if (fnt != NULL) {
1297                   if (fnt != curFont) {
1298                     curFont = fnt;
1299                     SelectFont (curFont);
1300                   }
1301                 }
1302               }
1303               color = FALSE;
1304               if (colorProc != NULL && (! force)) {
1305                 color = colorProc (d, item + 1, row + 1, col + 1);
1306                 if (! color) {
1307                   SetColor (currentColor);
1308                 }
1309               }
1310               invert = FALSE;
1311               if (invertProc != NULL && (! force)) {
1312                 invert = invertProc (d, item + 1, row + 1, col + 1);
1313               } else if (ddatptr->useRowsNotItems) {
1314                 invert = (Boolean) (ddatptr->firstHighlightItem <= row + 1 &&
1315                                     ddatptr->lastHighlightItem >= row + 1);
1316               } else {
1317                 invert = (Boolean) (ddatptr->firstHighlightItem <= item + 1 &&
1318                                     ddatptr->lastHighlightItem >= item + 1);
1319               }
1320               gray = FALSE;
1321               if (grayProc != NULL && (! force)) {
1322                 gray = grayProc (d, item + 1, row + 1, col + 1);
1323               }
1324               SelectFont (curFont);
1325               if (invert) {
1326                 InvertColors ();
1327                 EraseRect (&rct);
1328               }
1329               rct.left += insetLeft;
1330               rct.right -= insetRight;
1331               drw = rct;
1332               if (num > 0) {
1333                 while (num > 0 && *ptr == '\t') {
1334                   num--;
1335                   ptr++;
1336                   drw.left += CharWidth (' ') * tabCount;
1337                 }
1338                 if (ddatptr->drawcell != NULL) {
1339                   tmp = (CharPtr) MemNew((size_t)(num + 2));
1340                   if (tmp != NULL) {
1341                     MemCopy (tmp, ptr, num);
1342                     ddatptr->drawcell (d, item + 1, row + 1, col + 1, &drw, tmp, just, gray);
1343                     MemFree (tmp);
1344                   }
1345                 } else {
1346                   DrawText (&drw, ptr, num, just, gray);
1347                 }
1348               }
1349               if (invert) {
1350                 InvertColors ();
1351               }
1352               if (colorProc != NULL && (! force)) {
1353                 SetColor (currentColor);
1354               }
1355               rct.left -= insetLeft;
1356               rct.right += insetRight;
1357             }
1358           }
1359           ptr += num;
1360         }
1361         ch = *ptr;
1362       }
1363       if (drawBars) {
1364         InvertMode ();
1365         for (col = 0; col < itemPtr->numCols; col++) {
1366           rct.left = colFmt [col].position;
1367           rct.right = rct.left + colFmt [col].pixWidth;
1368           if (colFmt [col].bar) {
1369             drawBars = TRUE;
1370             MoveTo (rct.left, barTop);
1371 /*
1372 #ifdef WIN_MAC
1373             LineTo (rct.left, barBottom -1);
1374 #else
1375             LineTo (rct.left, barBottom);
1376 #endif
1377 */
1378             if (is_old_win) {
1379               LineTo (rct.left, barBottom);
1380             } else {
1381               LineTo (rct.left, barBottom - 1);
1382             }
1383           }
1384         }
1385         CopyMode ();
1386       }
1387       rct.top = rct.bottom;
1388       rsult = rct.top - r->top;
1389     }
1390     SelectFont (systemFont);
1391   }
1392   return rsult;
1393 }
1394 
1395 /*****************************************************************************
1396 *
1397 *   DrawDocument (d)
1398 *       Panel callback that traverses the item list and draws visible items
1399 *       Clipping is to the intersection of the updateRgn (the portion of the
1400 *       panel exposed) and the inset area of the document, leaving a four-
1401 *       pixel margin
1402 *
1403 *****************************************************************************/
1404 
1405 static void DrawDocument (PaneL d)
1406 
1407 {
1408   DocData  ddata;
1409   RegioN   dst;
1410   Int4     firstLine;
1411   Int2     highest;
1412   Int2     item;
1413   ItemPtr  itemPtr;
1414   Int2     lowest;
1415   Int2     numRows;
1416   Int4     off;
1417   Int2     pixels;
1418   RecT     r;
1419   RecT     rct;
1420   BaR      sb;
1421   RegioN   src;
1422 
1423   GetPanelExtra (d, &ddata);
1424   if (ddata.numItems > 0) {
1425     ObjectRect (d, &r);
1426     InsetRect (&r, 4, 4);
1427     sb = GetSlateVScrollBar ((SlatE) d);
1428     if (sb != NULL) {
1429       src = CreateRgn ();
1430       dst = CreateRgn ();
1431       LoadRectRgn (src, r.left, r.top, r.right, r.bottom);
1432       SectRgn (src, updateRgn, dst);
1433       ClipRgn (dst);
1434       DestroyRgn (src);
1435       DestroyRgn (dst);
1436       off = GetBarValue (sb);
1437       pixels = 0;
1438       lowest = INT2_MAX;
1439       highest = INT2_MIN;
1440       item = GetItemNum (&ddata, off);
1441       itemPtr = GetItemPtr (&ddata, item);
1442       if (itemPtr != NULL) {
1443         firstLine = off - itemPtr->startsAt;
1444         do {
1445           if (itemPtr != NULL) {
1446             if (itemPtr->neverCached) {
1447               CollectRange (item, &lowest, &highest);
1448             }
1449             CacheAndFormat (&ddata, item + 1, itemPtr, &r, ddata.tabCount);
1450             SetTablePixFormat (itemPtr->colFmt, r.left, itemPtr->numCols);
1451             if (pixels != 0) {
1452               r.top += itemPtr->leadHeight;
1453             }
1454             rct = r;
1455             numRows = MIN (itemPtr->numRows - firstLine,
1456                            MAX ((r.bottom - rct.top) / itemPtr->lineHeight, 0));
1457             rct.bottom = rct.top + itemPtr->lineHeight * (itemPtr->numRows - firstLine);
1458             if (updateRgn == NULL || RectInRgn (&rct, updateRgn)) {
1459               pixels = DrawTableItem ((DoC) d, &ddata, itemPtr, &r, item, firstLine,
1460                                       ddata.gray, ddata.invert, ddata.color,
1461                                       FALSE, ddata.tabCount);
1462               if (ddata.draw != NULL) {
1463                 rct.bottom = rct.top + itemPtr->lineHeight * numRows;
1464                 if (RectInRect (&rct, &r) &&
1465                     (updateRgn == NULL || RectInRgn (&rct, updateRgn))) {
1466                   ddata.draw ((DoC) d, &rct, item + 1, firstLine);
1467                 }
1468                 ResetDrawingTools ();
1469               }
1470             } else {
1471               pixels = rct.bottom - rct.top;
1472             }
1473             r.top += pixels;
1474           }
1475           item++;
1476           firstLine = 0;
1477           itemPtr = GetItemPtr (&ddata, item);
1478         } while (r.top < r.bottom && item < ddata.numItems && pixels > 0);
1479         if (lowest < INT2_MAX) {
1480           ddata.numLines = UpdateLineStarts (&ddata, lowest);
1481           SetPanelExtra (d, &ddata);
1482         }
1483       }
1484       ResetClip ();
1485     }
1486   }
1487   SelectFont (systemFont);
1488 }
1489 
1490 /*****************************************************************************
1491 *
1492 *   DocumentScrlProc (sb, s, newval, oldval)
1493 *       Scroll bar callback that takes suppressed partial lines into account
1494 *
1495 *****************************************************************************/
1496 
1497 static void DocumentScrlProc (BaR sb, SlatE s, Int4 newval, Int4 oldval)
1498 
1499 {
1500   Int4     barmax;
1501   Int4     barval;
1502   DocData  ddata;
1503   Int2     firstShown;
1504   Boolean  goToEnd;
1505   Int2     height;
1506   Int2     highest;
1507   Int2     highFree;
1508   Int2     item;
1509   ItemPtr  itemPtr;
1510   Int4     last;
1511   Int2     limit;
1512   Int2     line;
1513   Int2     lineInto;
1514   Int2     lowest;
1515   Int2     lowFree;
1516   Int4     min;
1517   Int2     pixels;
1518   Int2     pgDn;
1519   Int2     pgUp;
1520   RecT     r;
1521   Int2     vis;
1522 
1523   if (s != NULL && oldval != newval) {
1524     if (Visible (s) && AllParentsVisible (s)) {
1525       GetPanelExtra ((PaneL) s, &ddata);
1526       ObjectRect (s, &r);
1527       InsetRect (&r, 4, 4);
1528       height = r.bottom - r.top;
1529 
1530       Select (s);
1531       if (ddata.pgUp < 1 || ddata.pgDn < 1) {
1532         InsetRect (&r, -1, -1);
1533         InvalRect (&r);
1534       } else if ((newval > oldval && newval <= oldval + ddata.pgDn) ||
1535           (newval < oldval && newval >= oldval - ddata.pgUp)) {
1536         pixels = PixelsBetween (&ddata, &r, newval, oldval, NULL, NULL);
1537         if (ABS (pixels) < height) {
1538           min = MIN (oldval, newval);
1539           item = GetItemNum (&ddata, min);
1540           line = (Int2) (min - GetStartsAt (&ddata, item));
1541           vis = VisLinesBelow (&ddata, &r, item, line, NULL, NULL);
1542           last = min + vis - 1;
1543           limit = PixelsBetween (&ddata, &r, newval, last, NULL, NULL);
1544           item = GetItemNum (&ddata, last);
1545           line = (Int2) (last - GetStartsAt (&ddata, item));
1546           limit += GetLineHeight (&ddata, item);
1547           ScrollRect (&r, 0, pixels);
1548           r.top += limit;
1549           InsetRect (&r, -1, -1);
1550           InvalRect (&r);
1551         } else {
1552           InsetRect (&r, -1, -1);
1553           InvalRect (&r);
1554         }
1555       } else {
1556         InsetRect (&r, -1, -1);
1557         InvalRect (&r);
1558       }
1559 
1560       min = MIN (oldval, newval);
1561       item = GetItemNum (&ddata, min);
1562       ddata.numLines = UpdateLineStarts (&ddata, item);
1563       SetPanelExtra ((PaneL) s, &ddata);
1564 
1565       item = GetItemNum (&ddata, newval);
1566       line = (Int2) (newval - GetStartsAt (&ddata, item));
1567       firstShown = item;
1568       lineInto = line;
1569 
1570       barval = GetStartsAt (&ddata, firstShown) + lineInto;
1571       if (barval > ddata.barmax) {
1572         CorrectBarMax (sb, barval);
1573         CorrectBarValue (sb, barval);
1574       } else {
1575         CorrectBarValue (sb, barval);
1576       }
1577       Update ();
1578 
1579       lowest = INT2_MAX;
1580       highest = INT2_MIN;
1581       ObjectRect (s, &r);
1582       InsetRect (&r, 4, 4);
1583       pgUp = VisLinesAbove (&ddata, &r, firstShown, lineInto, &lowest, &highest) - 1;
1584       pgDn = VisLinesBelow (&ddata, &r, firstShown, lineInto, &lowest, &highest) - 1;
1585       if (pgDn < 1) {
1586         pgDn = 1;
1587       }
1588       if (pgUp < 1) {
1589         pgUp = 1;
1590       }
1591       /*
1592       item = GetItemNum (&ddata, newval + pgDn);
1593       line = (Int2) (newval + (Int4) pgDn - GetStartsAt (&ddata, item));
1594       VisLinesBelow (&ddata, &r, item, line, &lowest, &highest);
1595       */
1596       if (lowest < INT2_MAX) {
1597         ddata.numLines = UpdateLineStarts (&ddata, lowest);
1598         SetPanelExtra ((PaneL) s, &ddata);
1599       }
1600 
1601       lowFree = INT2_MAX;
1602       highFree = INT2_MIN;
1603       for (item = 0; item < lowest; item++) {
1604         FreeCachedItem (&ddata, item, &lowFree, &highFree);
1605       }
1606       for (item = highest + 1; item < ddata.numItems; item++) {
1607         FreeCachedItem (&ddata, item, &lowFree, &highFree);
1608       }
1609       if (lowFree < INT2_MAX) {
1610         ddata.numLines = UpdateLineStarts (&ddata, lowFree);
1611         SetPanelExtra ((PaneL) s, &ddata);
1612       }
1613 
1614       barmax = 0;
1615       goToEnd = (Boolean) (newval == ddata.barmax);
1616       if (ddata.numLines > 0 && ddata.numItems > 0) {
1617         itemPtr = GetItemPtr (&ddata, ddata.numItems - 1);
1618         if (itemPtr != NULL) {
1619           ObjectRect (s, &r);
1620           InsetRect (&r, 4, 4);
1621           lowest = INT2_MAX;
1622           highest = INT2_MIN;
1623           vis = VisLinesAbove (&ddata, &r, ddata.numItems - 1,
1624                                itemPtr->numRows - 1, &lowest, &highest);
1625           if (lowest < INT2_MAX) {
1626             ddata.numLines = UpdateLineStarts (&ddata, lowest);
1627             SetPanelExtra ((PaneL) s, &ddata);
1628           }
1629           barmax = ddata.numLines - vis;
1630         }
1631       }
1632       barval = GetStartsAt (&ddata, firstShown) + lineInto;
1633       if (goToEnd) {
1634         barval = barmax;
1635       }
1636       if (barval > ddata.barmax) {
1637         CorrectBarMax (sb, barmax);
1638         CorrectBarValue (sb, barval);
1639       } else {
1640         CorrectBarValue (sb, barval);
1641         CorrectBarMax (sb, barmax);
1642       }
1643       CorrectBarPage (sb, pgUp, pgDn);
1644       ddata.barmax = barmax;
1645       ddata.pgUp = pgUp;
1646       ddata.pgDn = pgDn;
1647       SetPanelExtra ((PaneL) s, &ddata);
1648       Update ();
1649       if (ddata.pan != NULL) {
1650         Select (s);
1651         ddata.pan ((DoC) s);
1652       }
1653     }
1654   }
1655 }
1656 
1657 /*****************************************************************************
1658 *
1659 *   CreateItemPtr (d, item)
1660 *       Adds an item slot to the item list
1661 *
1662 *****************************************************************************/
1663 
1664 static ItemPtr CreateItemPtr (DoC d, Int2 item)
1665 
1666 {
1667   DocData    ddata;
1668   Int2       index;
1669   Int2       list;
1670   ItemPtr    itemPtr;
1671   ListDPtr   listPtr;
1672   MasterPtr  masterPtr;
1673 
1674   itemPtr = NULL;
1675   if (d != NULL && item < 32767) {
1676     GetPanelExtra ((PaneL) d, &ddata);
1677     if (ddata.master == NULL) {
1678       ddata.master = (MasterPtr) MemNew (sizeof (MasterData));
1679       SetPanelExtra ((PaneL) d, &ddata);
1680     }
1681     list = (item / LISTSIZE);
1682     if (list < MAXLISTS && ddata.master != NULL) {
1683       masterPtr = ddata.master;
1684       listPtr = masterPtr->list [list];
1685       if (listPtr == NULL) {
1686         masterPtr->list [list] = (ListDPtr) MemNew(sizeof(ListData));
1687         listPtr = masterPtr->list [list];
1688       }
1689       if (listPtr != NULL) {
1690         index = (item % LISTSIZE);
1691         itemPtr = &(listPtr->items [index]);
1692       }
1693     }
1694   }
1695   return itemPtr;
1696 }
1697 
1698 /*****************************************************************************
1699 *
1700 *   GetFontHeight (font)
1701 *       Returns the pixel height of a font, caching for quicker access
1702 *
1703 *****************************************************************************/
1704 
1705 static Int2 GetFontHeight (FonT font)
1706 
1707 {
1708   Int2  height;
1709   Int2  i;
1710 
1711   height = 0;
1712   i = 0;
1713   while (i < MAXFONTS && fontHeights [i].font != font && fontHeights [i].font != NULL) {
1714     i++;
1715   }
1716   if (fontHeights [i].font == font) {
1717     height = fontHeights [i].height;
1718   } else {
1719     SelectFont (font);
1720     height = LineHeight ();
1721     if (i < MAXFONTS) {
1722       fontHeights [i].font = font;
1723       fontHeights [i].height = height;
1724     }
1725   }
1726   return height;
1727 }
1728 
1729 /*****************************************************************************
1730 *
1731 *   UpdateItemHeights (itemPtr)
1732 *       Returns the maximum height of all fonts used in an item
1733 *
1734 *****************************************************************************/
1735 
1736 static void UpdateItemHeights (ItemPtr itemPtr)
1737 
1738 {
1739   ColXPtr  colFmt;
1740   FonT     fnt;
1741   Int2     i;
1742   Int2     linhgt;
1743   Int2     maxhgt;
1744 
1745   if (itemPtr != NULL) {
1746     colFmt = itemPtr->colFmt;
1747     maxhgt = 0;
1748     if (colFmt != NULL) {
1749       i = itemPtr->numCols;
1750       while (i > 0) {
1751         i--;
1752         fnt = colFmt [i].font;
1753         if (fnt != NULL) {
1754           linhgt = GetFontHeight (fnt);
1755           if (linhgt > maxhgt) {
1756             maxhgt = linhgt;
1757           }
1758         } else if (itemPtr->font == NULL) {
1759           linhgt = stdLineHeight;
1760           if (linhgt > maxhgt) {
1761             maxhgt = linhgt;
1762           }
1763         }
1764       }
1765     }
1766     fnt = itemPtr->font;
1767     if (fnt != NULL) {
1768       linhgt = GetFontHeight (fnt);
1769       if (linhgt > maxhgt) {
1770         maxhgt = linhgt;
1771       }
1772     }
1773     if (maxhgt == 0) {
1774       maxhgt = stdLineHeight;
1775     }
1776     itemPtr->lineHeight = MAX (maxhgt, itemPtr->minHeight);
1777     if (itemPtr->openSpace) {
1778       itemPtr->leadHeight = maxhgt;
1779     } else {
1780       itemPtr->leadHeight = 0;
1781     }
1782   }
1783 }
1784 
1785 /*****************************************************************************
1786 *
1787 *   SetDocAutoAdjust (d, autoAdjust)
1788 *       Sets the document automatic scroll adjust parameter
1789 *
1790 *****************************************************************************/
1791 
1792 extern void SetDocAutoAdjust (DoC d, Boolean autoAdjust)
1793 
1794 {
1795   DocData  ddata;
1796 
1797   if (d != NULL) {
1798     GetPanelExtra ((PaneL) d, &ddata);
1799     ddata.autoAdjust = autoAdjust;
1800     SetPanelExtra ((PaneL) d, &ddata);
1801   }
1802 }
1803 
1804 /* dgg here -- want to make use of tab settings other than from FancyFile call */
1805 
1806 /*****************************************************************************
1807 *
1808 *   Nlm_SetDocTabstops (d, tabStops)
1809 *       Sets the document tap stop interval
1810 *
1811 *****************************************************************************/
1812 
1813 extern void Nlm_SetDocTabstops (DoC d, Int2 tabStops)
1814 {
1815   DocData  ddata;
1816 
1817   if (d != NULL) {
1818     GetPanelExtra ((PaneL) d, &ddata);
1819     ddata.tabCount = tabStops;
1820     SetPanelExtra ((PaneL) d, &ddata);
1821   }
1822 }
1823 
1824 /*****************************************************************************
1825 *
1826 *   AdjustDocScroll (d)
1827 *       Calculates an estimate for the scroll bar maximum
1828 *
1829 *****************************************************************************/
1830 
1831 extern void AdjustDocScroll (DoC d)
1832 
1833 {
1834   Int4     barmax;
1835   Int4     barval;
1836   DocData  ddata;
1837   Int2     firstShown;
1838   Int2     highest;
1839   Int2     item;
1840   ItemPtr  itemPtr;
1841   Int2     line;
1842   Int2     lineInto;
1843   Int2     lowest;
1844   Int2     pgDn;
1845   Int2     pgUp;
1846   RecT     r;
1847   BaR      sb;
1848   Int2     vis;
1849 
1850   if (d != NULL) {
1851     GetPanelExtra ((PaneL) d, &ddata);
1852     SelectFont (systemFont);
1853     sb = GetSlateVScrollBar ((SlatE) d);
1854     if (sb != NULL) {
1855       if (ddata.numLines > 0 && ddata.numItems > 0) {
1856         ObjectRect (d, &r);
1857         InsetRect (&r, 4, 4);
1858         barval = GetBarValue (sb);
1859         item = GetItemNum (&ddata, barval);
1860         line = (Int2) (barval - GetStartsAt (&ddata, item));
1861         firstShown = item;
1862         lineInto = line;
1863         lowest = INT2_MAX;
1864         highest = INT2_MIN;
1865         itemPtr = GetItemPtr (&ddata, ddata.numItems - 1);
1866         if (itemPtr != NULL) {
1867           CacheIfNever (&ddata, ddata.numItems, itemPtr, &r, ddata.tabCount);
1868           vis = VisLinesAbove (&ddata, &r, ddata.numItems - 1,
1869                                itemPtr->numRows - 1, &lowest, &highest);
1870         }
1871         pgUp = VisLinesAbove (&ddata, &r, firstShown, lineInto, &lowest, &highest) - 1;
1872         pgDn = VisLinesBelow (&ddata, &r, firstShown, lineInto, &lowest, &highest) - 1;
1873         if (pgDn < 1) {
1874           pgDn = 1;
1875         }
1876         if (pgUp < 1) {
1877           pgUp = 1;
1878         }
1879         /*
1880         item = GetItemNum (&ddata, barval + pgDn);
1881         line = (Int2) (barval + (Int4) pgDn - GetStartsAt (&ddata, item));
1882         VisLinesBelow (&ddata, &r, item, line, &lowest, &highest);
1883         */
1884         if (lowest < INT2_MAX) {
1885           ddata.numLines = UpdateLineStarts (&ddata, lowest);
1886           SetPanelExtra ((PaneL) d, &ddata);
1887         }
1888         itemPtr = GetItemPtr (&ddata, ddata.numItems - 1);
1889         if (itemPtr != NULL) {
1890           barmax = 0;
1891           ObjectRect (d, &r);
1892           InsetRect (&r, 4, 4);
1893           lowest = INT2_MAX;
1894           highest = INT2_MIN;
1895           vis = VisLinesAbove (&ddata, &r, ddata.numItems - 1,
1896                                itemPtr->numRows - 1, &lowest, &highest);
1897           if (lowest < INT2_MAX) {
1898             ddata.numLines = UpdateLineStarts (&ddata, lowest);
1899             SetPanelExtra ((PaneL) d, &ddata);
1900           }
1901           barmax = ddata.numLines - vis;
1902           barval = GetStartsAt (&ddata, firstShown) + lineInto;
1903           CorrectBarPage (sb, pgUp, pgDn);
1904           if (barval > ddata.barmax) {
1905             CorrectBarMax (sb, barmax);
1906             CorrectBarValue (sb, barval);
1907           } else {
1908             CorrectBarValue (sb, barval);
1909             CorrectBarMax (sb, barmax);
1910           }
1911           ddata.barmax = barmax;
1912           ddata.pgUp = pgUp;
1913           ddata.pgDn = pgDn;
1914           SetPanelExtra ((PaneL) d, &ddata);
1915         }
1916       } else {
1917         Reset (sb);
1918       }
1919     }
1920   }
1921 }
1922 
1923 /*****************************************************************************
1924 *
1925 *   ForceFormat (d, item)
1926 *       Forces text format
1927 *
1928 *****************************************************************************/
1929 
1930 extern void ForceFormat (DoC d, Int2 item)
1931 
1932 {
1933   DocData  ddata;
1934   ItemPtr  itemPtr;
1935   RecT     r;
1936 
1937   if (d != NULL && item > 0) {
1938     GetPanelExtra ((PaneL) d, &ddata);
1939     itemPtr = GetItemPtr (&ddata, item - 1);
1940     if (itemPtr != NULL) {
1941       ObjectRect (d, &r);
1942       InsetRect (&r, 4, 4);
1943       itemPtr->text = (CharPtr) MemFree (itemPtr->text);
1944       itemPtr->notCached = TRUE;
1945       itemPtr->neverCached = TRUE;
1946       SetTablePixFormat (itemPtr->colFmt, r.left, itemPtr->numCols);
1947       FormatText (&ddata, item, itemPtr, TRUE, ddata.tabCount);
1948       UpdateItemHeights (itemPtr);
1949       ddata.numLines = UpdateLineStarts (&ddata, 0);
1950       SetPanelExtra ((PaneL) d, &ddata);
1951       if (ddata.autoAdjust) {
1952         AdjustDocScroll (d);
1953       }
1954     }
1955   }
1956 }
1957 
1958 /*****************************************************************************
1959 *
1960 *   defaultTable
1961 *       Column format used if the colFmt parameter is NULL
1962 *
1963 *****************************************************************************/
1964 
1965 static ColData defaultTable = {0, 0, 0, 0, NULL, 'l',
1966                                TRUE, FALSE, FALSE, FALSE, TRUE};
1967 
1968 /*****************************************************************************
1969 *
1970 *   CacheColFmt (d, colFmt)
1971 *       Caches the colFmt format structure
1972 *
1973 *****************************************************************************/
1974 
1975 static ColXPtr CacheColFmt (DoC d, ColPtr colFmt)
1976 
1977 {
1978   DocData     ddata;
1979   Boolean     found;
1980   Boolean     goOn;
1981   Int2        i;
1982   Int2        numCols;
1983   ColXPtr     rsult;
1984   ColXPtr     thisCol;
1985   ValNodePtr  vnp;
1986 
1987   rsult = NULL;
1988   if (d != NULL && colFmt != NULL) {
1989     i = 0;
1990     while (! colFmt [i].last) {
1991       i++;
1992     }
1993     i++;
1994     numCols = i;
1995     rsult = (ColXPtr) MemNew (numCols * sizeof (ColXData));
1996     if (rsult != NULL) {
1997       for (i = 0; i < numCols; i++) {
1998         rsult [i].position = 0;
1999         rsult [i].pixWidth = colFmt [i].pixWidth;
2000         rsult [i].pixInset = colFmt [i].pixInset;
2001         rsult [i].charWidth = colFmt [i].charWidth;
2002         rsult [i].charInset = colFmt [i].charInset;
2003         if (colFmt [i].just == 'l') {
2004           rsult [i].just = JUST_LEFT;
2005         } else if (colFmt [i].just == 'c') {
2006           rsult [i].just = JUST_CENTER;
2007         } else if (colFmt [i].just == 'r') {
2008           rsult [i].just = JUST_RIGHT;
2009         } else {
2010           rsult [i].just = JUST_LEFT;
2011         }
2012         rsult [i].font = colFmt [i].font;
2013         rsult [i].zeroWidth = (Boolean) (colFmt [i].pixWidth == 0);
2014         if (rsult [i].zeroWidth) {
2015           rsult [i].charWidth = 0;
2016         }
2017         rsult [i].wrap = colFmt [i].wrap;
2018         rsult [i].bar = colFmt [i].bar;
2019         rsult [i].underline = colFmt [i].underline;
2020         rsult [i].left = colFmt [i].left;
2021         rsult [i].last = colFmt [i].last;
2022       }
2023       GetPanelExtra ((PaneL) d, &ddata);
2024       vnp = ddata.colFmts;
2025       goOn = TRUE;
2026       while (vnp != NULL && goOn) {
2027         thisCol = (ColXPtr) vnp->data.ptrvalue;
2028         if (thisCol != NULL) {
2029           i = 0;
2030           while (! thisCol [i].last) {
2031             i++;
2032           }
2033           i++;
2034           if (i == numCols) {
2035             found = TRUE;
2036             for (i = 0; i < numCols; i++) {
2037               if (thisCol [i].zeroWidth) {
2038                 thisCol [i].pixWidth = 0;
2039                 thisCol [i].charWidth = 0;
2040               }
2041               if (thisCol [i].font != rsult [i].font ||
2042                   thisCol [i].pixWidth != rsult [i].pixWidth ||
2043                   thisCol [i].pixInset != rsult [i].pixInset ||
2044                   thisCol [i].charWidth != rsult [i].charWidth ||
2045                   thisCol [i].charInset != rsult [i].charInset ||
2046                   thisCol [i].just != rsult [i].just ||
2047                   thisCol [i].zeroWidth != rsult [i].zeroWidth ||
2048                   thisCol [i].wrap != rsult [i].wrap ||
2049                   thisCol [i].bar != rsult [i].bar ||
2050                   thisCol [i].underline != rsult [i].underline ||
2051                   thisCol [i].left != rsult [i].left ||
2052                   thisCol [i].last != rsult [i].last) {
2053                 found = FALSE;
2054               }
2055             }
2056             if (found) {
2057               goOn = FALSE;
2058             }
2059           }
2060         }
2061         if (goOn) {
2062           vnp = vnp->next;
2063         }
2064       }
2065       if (goOn) {
2066         vnp = ValNodeNew (ddata.colFmts);
2067         if (vnp != NULL) {
2068           vnp->data.ptrvalue = (Pointer) rsult;
2069         }
2070         if (ddata.colFmts == NULL) {
2071           ddata.colFmts = vnp;
2072           SetPanelExtra ((PaneL) d, &ddata);
2073         }
2074       } else {
2075         MemFree (rsult);
2076         rsult = (ColXPtr) vnp->data.ptrvalue;
2077       }
2078     }
2079   }
2080   return rsult;
2081 }
2082 
2083 /*****************************************************************************
2084 *
2085 *   UpdateColFmt (d, *col)
2086 *       Returns the maximum height of all fonts used in an item
2087 *
2088 *****************************************************************************/
2089 
2090 extern void UpdateColFmt (DoC d, ColPtr col)
2091 
2092 {
2093   DocData  dd;
2094   ItemPtr  itemPtr;
2095   Int2     item;
2096 
2097   GetPanelExtra ((PaneL) d, &dd);
2098   for (item = 0; item < dd.numItems; item++) {
2099     itemPtr = GetItemPtr (&dd, item);
2100     if (itemPtr != NULL) {
2101       itemPtr->colFmt = CacheColFmt (d, col);
2102     }
2103   }
2104   SetPanelExtra ((PaneL) d, &dd);
2105 }
2106 
2107 /*****************************************************************************
2108 *
2109 *   SetDocDefaults (d, defaultParFmt, defaultColFmt, defaultFont)
2110 *       Sets default format preferences, so AppendItem, etc., can pass NULLs
2111 *
2112 *****************************************************************************/
2113 
2114 extern void SetDocDefaults (DoC d, ParPtr defaultParFmt,
2115                             ColPtr defaultColFmt, FonT defaultFont)
2116 
2117 {
2118   DocData  ddata;
2119 
2120   if (d != NULL) {
2121     GetPanelExtra ((PaneL) d, &ddata);
2122     ddata.defaultParFmt = defaultParFmt;
2123     ddata.defaultColFmt = defaultColFmt;
2124     ddata.defaultFont = defaultFont;
2125     SetPanelExtra ((PaneL) d, &ddata);
2126   }
2127 }
2128 
2129 /*****************************************************************************
2130 *
2131 *   SetDocSimpleMode (d, useRowsNotItems)
2132 *       Sets default highlighting range
2133 *
2134 *****************************************************************************/
2135 
2136 extern void SetDocSimpleMode (DoC d, Boolean useRowsNotItems)
2137 
2138 {
2139   DocData  ddata;
2140 
2141   if (d != NULL) {
2142     GetPanelExtra ((PaneL) d, &ddata);
2143     ddata.useRowsNotItems = useRowsNotItems;
2144     SetPanelExtra ((PaneL) d, &ddata);
2145   }
2146 }
2147 /*****************************************************************************
2148 *
2149 *   SetDocHighlight (d, firstItem, lastItem)
2150 *       Sets default highlighting range
2151 *
2152 *****************************************************************************/
2153 
2154 extern void SetDocHighlight (DoC d, Int2 firstItem, Int2 lastItem)
2155 
2156 {
2157   DocData  ddata;
2158 
2159   if (d != NULL) {
2160     GetPanelExtra ((PaneL) d, &ddata);
2161     ddata.firstHighlightItem = MIN (firstItem, lastItem);
2162     ddata.lastHighlightItem = MAX (firstItem, lastItem);
2163     SetPanelExtra ((PaneL) d, &ddata);
2164   }
2165 }
2166 
2167 /*****************************************************************************
2168 *
2169 *   GetDocHighlight (d, firstItem, lastItem)
2170 *       Returns default highlighting range
2171 *
2172 *****************************************************************************/
2173 
2174 extern void GetDocHighlight (DoC d, Int2Ptr firstItem, Int2Ptr lastItem)
2175 
2176 {
2177   DocData  ddata;
2178 
2179   if (d != NULL) {
2180     GetPanelExtra ((PaneL) d, &ddata);
2181     if (firstItem != NULL) {
2182       *firstItem = ddata.firstHighlightItem;
2183     }
2184     if (lastItem != NULL) {
2185       *lastItem = ddata.lastHighlightItem;
2186     }
2187   }
2188 }
2189 
2190 /*****************************************************************************
2191 *
2192 *   SetDocNotify (d, notify)
2193 *       Sets default click notification
2194 *
2195 *****************************************************************************/
2196 
2197 static void DefaultNotifyClickProc (DoC d, PoinT pt)
2198 
2199 {
2200   Int2     col;
2201   DocData  ddata;
2202   Int2     item;
2203   Int2     row;
2204 
2205   if (d != NULL) {
2206     GetPanelExtra ((PaneL) d, &ddata);
2207     if (ddata.notify != NULL) {
2208       MapDocPoint (d, pt, &item, &row, &col, NULL);
2209       ddata.notify (d, item, row, col, dblClick);
2210     }
2211   }
2212 }
2213 
2214 extern void SetDocNotify (DoC d, DocNotfyProc notify)
2215 
2216 {
2217   DocData  ddata;
2218 
2219   if (d != NULL) {
2220     GetPanelExtra ((PaneL) d, &ddata);
2221     ddata.notify = notify;
2222     SetPanelExtra ((PaneL) d, &ddata);
2223     Nlm_SetPanelClick ((PaneL) d, (PnlClckProc) DefaultNotifyClickProc, NULL, NULL, NULL);
2224   }
2225 }
2226 
2227 /*****************************************************************************
2228 *
2229 *   SetupItem (d, ddatptr, itemPtr, proc, data, docOwnsData,
2230 *              lines, parFmt, colFmt, font)
2231 *       Processes user parameters into an item to append or insert into
2232 *       the item list, or replace an item currently in the item list
2233 *
2234 *****************************************************************************/
2235 
2236 static void SetupItem (DoC d, DocDataPtr ddatptr, ItemPtr itemPtr, DocPrntProc proc,
2237                        Pointer data, Boolean docOwnsData, Int2 lines,
2238                        ParPtr parFmt, ColPtr colFmt, FonT font)
2239 
2240 {
2241   Int2  i;
2242   RecT  r;
2243 
2244   if (d != NULL && ddatptr != NULL && itemPtr != NULL && proc != NULL) {
2245     ObjectRect (d, &r);
2246     InsetRect (&r, 4, 4);
2247     itemPtr->prtProc = proc;
2248     itemPtr->dataPtr = data;
2249     itemPtr->text = NULL;
2250     if (font == NULL) {
2251       font = ddatptr->defaultFont;
2252     }
2253     itemPtr->font = font;
2254     if (colFmt == NULL) {
2255       colFmt = ddatptr->defaultColFmt;
2256     }
2257     if (colFmt == NULL) {
2258       defaultTable.pixWidth = r.right - r.left;
2259       defaultTable.charWidth = 80;
2260       colFmt = &defaultTable;
2261     }
2262     i = 0;
2263     while (! colFmt [i].last) {
2264       i++;
2265     }
2266     i++;
2267     itemPtr->numCols = i;
2268     itemPtr->numRows = MAX (lines, 1);
2269     itemPtr->colFmt = CacheColFmt (d, colFmt);
2270     itemPtr->extra = NULL;
2271     itemPtr->startsAt = 0;
2272     if (parFmt == NULL) {
2273       parFmt = ddatptr->defaultParFmt;
2274     }
2275     if (parFmt != NULL) {
2276       itemPtr->openSpace = parFmt->openSpace;
2277       itemPtr->keepWithNext = parFmt->keepWithNext;
2278       itemPtr->keepTogether = parFmt->keepTogether;
2279       itemPtr->newPage = parFmt->newPage;
2280       itemPtr->tabStops = parFmt->tabStops;
2281       itemPtr->minLines = MAX (parFmt->minLines, (Int2) 1);
2282       itemPtr->minHeight = parFmt->minHeight;
2283     } else {
2284       itemPtr->openSpace = TRUE;
2285       itemPtr->keepWithNext = FALSE;
2286       itemPtr->keepTogether = FALSE;
2287       itemPtr->newPage = FALSE;
2288       itemPtr->tabStops = FALSE;
2289       itemPtr->minLines = 0;
2290       itemPtr->minHeight = 0;
2291     }
2292     itemPtr->docOwnsData = docOwnsData;
2293     itemPtr->notCached = TRUE;
2294     itemPtr->neverCached = TRUE;
2295   }
2296 }
2297 
2298 /*****************************************************************************
2299 *
2300 *   AppendItem (d, proc, data, docOwnsData, lines,
2301 *               parFmt, colFmt, font)
2302 *       Processes user parameters and appends the item to the end of the
2303 *       item list
2304 *
2305 *****************************************************************************/
2306 
2307 extern void AppendItem (DoC d, DocPrntProc proc, Pointer data,
2308                         Boolean docOwnsData, Int2 lines,
2309                         ParPtr parFmt, ColPtr colFmt, FonT font)
2310 
2311 {
2312   DocData   ddata;
2313   ItemData  itemData;
2314   ItemPtr   itemPtr;
2315 
2316   if (d != NULL && proc != NULL) {
2317     GetPanelExtra ((PaneL) d, &ddata);
2318     MemFill (&itemData, 0, sizeof (ItemData));
2319     SetupItem (d, &ddata, &itemData, proc, data, docOwnsData,
2320                lines, parFmt, colFmt, font);
2321     if (ddata.upd != NULL) {
2322       ddata.upd (d, ddata.numItems, 0);
2323     }
2324     itemPtr = CreateItemPtr (d, ddata.numItems);
2325     GetPanelExtra ((PaneL) d, &ddata);
2326     if (itemPtr != NULL) {
2327       *itemPtr = *(&itemData);
2328       itemPtr->startsAt = ddata.numLines;
2329       UpdateItemHeights (itemPtr);
2330       ddata.numLines += itemPtr->numRows;
2331       (ddata.numItems)++;
2332       SetPanelExtra ((PaneL) d, &ddata);
2333       if (ddata.autoAdjust) {
2334         AdjustDocScroll (d);
2335       }
2336     }
2337   }
2338 }
2339 
2340 /*****************************************************************************
2341 *
2342 *   ReplaceItem (d, item, proc, data, docOwnsData,
2343 *                lines, parFmt, colFmt, font)
2344 *       Replaces an existing item in a document
2345 *
2346 *****************************************************************************/
2347 
2348 extern void ReplaceItem (DoC d, Int2 item, DocPrntProc proc,
2349                          Pointer data, Boolean docOwnsData, Int2 lines,
2350                          ParPtr parFmt, ColPtr colFmt, FonT font)
2351 
2352 {
2353   DocData  ddata;
2354   ItemPtr  itemPtr;
2355   Int4     startsAt;
2356 
2357   if (d != NULL && proc != NULL) {
2358     GetPanelExtra ((PaneL) d, &ddata);
2359     if (item > 0 && item <= ddata.numItems) {
2360       item--;
2361       if (ddata.upd != NULL) {
2362         ddata.upd (d, item, item);
2363       }
2364       itemPtr = GetItemPtr (&ddata, item);
2365       if (itemPtr != NULL) {
2366         startsAt = itemPtr->startsAt;
2367         itemPtr->text = (CharPtr) MemFree (itemPtr->text);
2368         if (itemPtr->docOwnsData) {
2369           itemPtr->dataPtr = (Pointer) MemFree (itemPtr->dataPtr);
2370         } else {
2371           itemPtr->dataPtr = NULL;
2372         }
2373         itemPtr->extra = MemFree (itemPtr->extra);
2374         MemFill (itemPtr, 0, sizeof (ItemData));
2375         SetupItem (d, &ddata, itemPtr, proc, data, docOwnsData,
2376                    lines, parFmt, colFmt, font);
2377         itemPtr->startsAt = startsAt;
2378         UpdateItemHeights (itemPtr);
2379         ddata.numLines = UpdateLineStarts (&ddata, item);
2380         SetPanelExtra ((PaneL) d, &ddata);
2381         if (ddata.autoAdjust) {
2382           AdjustDocScroll (d);
2383         }
2384       }
2385     }
2386   }
2387 }
2388 
2389 /*****************************************************************************
2390 *
2391 *   InsertItem (d, item, proc, data, docOwnsData,
2392 *               lines, parFmt, colFmt, font)
2393 *       Inserts a new item into a document
2394 *
2395 *****************************************************************************/
2396 
2397 extern void InsertItem (DoC d, Int2 item, DocPrntProc proc,
2398                         Pointer data, Boolean docOwnsData, Int2 lines,
2399                         ParPtr parFmt, ColPtr colFmt, FonT font)
2400 
2401 {
2402   DocData  ddata;
2403   ItemPtr  fromItem;
2404   ItemPtr  itemPtr;
2405   Int2     j;
2406   Int4     startsAt;
2407   ItemPtr  toItem;
2408 
2409   if (d != NULL && proc != NULL) {
2410     GetPanelExtra ((PaneL) d, &ddata);
2411     if (item > 0 && item <= ddata.numItems) {
2412       item--;
2413       if (ddata.upd != NULL) {
2414         ddata.upd (d, item, 0);
2415       }
2416       itemPtr = CreateItemPtr (d, ddata.numItems);
2417       if (itemPtr != NULL) {
2418         GetPanelExtra ((PaneL) d, &ddata);
2419         (ddata.numItems)++;
2420         SetPanelExtra ((PaneL) d, &ddata);
2421         for (j = ddata.numItems - 1; j > item; j--) {
2422           fromItem = GetItemPtr (&ddata, j - 1);
2423           toItem = GetItemPtr (&ddata, j);
2424           if (fromItem != NULL && toItem != NULL) {
2425             *toItem = *fromItem;
2426           }
2427         }
2428         itemPtr = GetItemPtr (&ddata, item);
2429         if (itemPtr != NULL) {
2430           startsAt = itemPtr->startsAt;
2431           MemFill (itemPtr, 0, sizeof (ItemData));
2432           SetupItem (d, &ddata, itemPtr, proc, data, docOwnsData,
2433                      lines, parFmt, colFmt, font);
2434           itemPtr->startsAt = startsAt;
2435           UpdateItemHeights (itemPtr);
2436           ddata.numLines = UpdateLineStarts (&ddata, item);
2437           SetPanelExtra ((PaneL) d, &ddata);
2438           if (ddata.autoAdjust) {
2439             AdjustDocScroll (d);
2440           }
2441         }
2442       }
2443     }
2444   }
2445 }
2446 
2447 /*****************************************************************************
2448 *
2449 *   CharPrtProc (ptr)
2450 *       Standard print function used with AppendText
2451 *
2452 *****************************************************************************/
2453 
2454 static CharPtr CharPrtProc (DoC d, Int2 item, Pointer ptr)
2455 
2456 {
2457   if (ptr != NULL) {
2458     return StringSave( (CharPtr)ptr );
2459   } else {
2460     return NULL;
2461   }
2462 }
2463 
2464 /*****************************************************************************
2465 *
2466 *   SkipPastNewLine (text, cnt)
2467 *       Finds the end of a line of text, up to a maximum number of characters
2468 *
2469 *****************************************************************************/
2470 
2471 static Int2 SkipPastNewLine (CharPtr text, Int2 cnt)
2472 
2473 {
2474   Char  ch;
2475 
2476   ch = *(text + cnt);
2477   while (ch != '\0' && ch != '\n' && cnt < 24380) {
2478     cnt++;
2479     ch = *(text + cnt);
2480   }
2481   while ((ch == '\n' || ch == '\r') && cnt < 24380) {
2482     cnt++;
2483     ch = *(text + cnt);
2484   }
2485   return cnt;
2486 }
2487 
2488 /*****************************************************************************
2489 *
2490 *   AppendText (d, text, parFmt, colFmt, font)
2491 *       Special case of AppendItem that takes formatted text as its data
2492 *
2493 *****************************************************************************/
2494 
2495 extern void AppendText (DoC d, CharPtr text, ParPtr parFmt,
2496                         ColPtr colFmt, FonT font)
2497 
2498 {
2499   Int2     cnt;
2500   Int2     cntr;
2501   Int2     start;
2502   Pointer  txt;
2503 
2504   if (d != NULL) {
2505     if (text != NULL && *text != '\0') {
2506       start = 0;
2507       cntr = StringLen (text);
2508       cnt = MIN (cntr, 24000);
2509       cnt = SkipPastNewLine (text + start, cnt);
2510       while (cnt > 0) {
2511         txt = MemNew (cnt + 1);
2512         MemCopy (txt, text + start, cnt);
2513         ProgMon ("AppendText");
2514         AppendItem (d, CharPrtProc, txt, TRUE, (cnt / 50) + 1,
2515                     parFmt, colFmt, font);
2516         start += cnt;
2517         cntr -= cnt;
2518         cnt = MIN (cntr, 24000);
2519         cnt = SkipPastNewLine (text + start, cnt);
2520       }
2521     } else {
2522       ProgMon ("AppendText");
2523       AppendItem (d, CharPrtProc, "", FALSE, 1,
2524                   parFmt, colFmt, font);
2525     }
2526   }
2527 }
2528 
2529 /*****************************************************************************
2530 *
2531 *   ReplaceText (d, item, text, parFmt, colFmt, font)
2532 *       Special case of ReplaceItem that takes formatted text as its data
2533 *
2534 *****************************************************************************/
2535 
2536 extern void ReplaceText (DoC d, Int2 item, CharPtr text,
2537                          ParPtr parFmt, ColPtr colFmt, FonT font)
2538 
2539 {
2540   Int2     cnt;
2541   Int2     cntr;
2542   Int2     start;
2543   Pointer  txt;
2544 
2545   if (d != NULL) {
2546     if (text != NULL && *text != '\0') {
2547       start = 0;
2548       cntr = StringLen (text);
2549       cnt = MIN (cntr, 24000);
2550       cnt = SkipPastNewLine (text + start, cnt);
2551       while (cnt > 0) {
2552         txt = MemNew (cnt + 1);
2553         MemCopy (txt, text + start, cnt);
2554         ReplaceItem (d, item, CharPrtProc, txt, TRUE, (cnt / 50) + 1,
2555                      parFmt, colFmt, font);
2556         start += cnt;
2557         cntr -= cnt;
2558         cnt = MIN (cntr, 24000);
2559         cnt = SkipPastNewLine (text + start, cnt);
2560         item++;
2561       }
2562     } else {
2563       ReplaceItem (d, item, CharPrtProc, "", FALSE, 1,
2564                    parFmt, colFmt, font);
2565     }
2566   }
2567 }
2568 
2569 /*****************************************************************************
2570 *
2571 *   InsertText (d, item, text, parFmt, colFmt, font)
2572 *       Special case of InsertItem that takes formatted text as its data
2573 *
2574 *****************************************************************************/
2575 
2576 extern void InsertText (DoC d, Int2 item, CharPtr text,
2577                         ParPtr parFmt, ColPtr colFmt, FonT font)
2578 
2579 {
2580   Int2     cnt;
2581   Int2     cntr;
2582   Int2     start;
2583   Pointer  txt;
2584 
2585   if (d != NULL) {
2586     if (text != NULL && *text != '\0') {
2587       start = 0;
2588       cntr = StringLen (text);
2589       cnt = MIN (cntr, 24000);
2590       cnt = SkipPastNewLine (text + start, cnt);
2591       while (cnt > 0) {
2592         txt = MemNew (cnt + 1);
2593         MemCopy (txt, text + start, cnt);
2594         InsertItem (d, item, CharPrtProc, txt, TRUE, (cnt / 50) + 1,
2595                     parFmt, colFmt, font);
2596         start += cnt;
2597         cntr -= cnt;
2598         cnt = MIN (cntr, 24000);
2599         cnt = SkipPastNewLine (text + start, cnt);
2600         item++;
2601       }
2602     } else {
2603       InsertItem (d, item, CharPrtProc, "", FALSE, 1,
2604                   parFmt, colFmt, font);
2605     }
2606   }
2607 }
2608 
2609 /*****************************************************************************
2610 *
2611 *   DeleteItem (d, item)
2612 *       Deletes an item from a document
2613 *
2614 *****************************************************************************/
2615 
2616 extern void DeleteItem (DoC d, Int2 item)
2617 
2618 {
2619   DocData  ddata;
2620   ItemPtr  fromItem;
2621   ItemPtr  itemPtr;
2622   Int2     j;
2623   Int4     startsAt;
2624   ItemPtr  toItem;
2625 
2626   if (d != NULL) {
2627     GetPanelExtra ((PaneL) d, &ddata);
2628     if (item > 0 && item <= ddata.numItems) {
2629       item--;
2630       itemPtr = GetItemPtr (&ddata, item);
2631       if (itemPtr != NULL) {
2632         startsAt = itemPtr->startsAt;
2633         itemPtr->text = (CharPtr) MemFree (itemPtr->text);
2634         if (itemPtr->docOwnsData) {
2635           itemPtr->dataPtr = (Pointer) MemFree (itemPtr->dataPtr);
2636         } else {
2637           itemPtr->dataPtr = NULL;
2638         }
2639         itemPtr->extra = MemFree (itemPtr->extra);
2640         for (j = item; j < ddata.numItems - 1; j++) {
2641           fromItem = GetItemPtr (&ddata, j + 1);
2642           toItem = GetItemPtr (&ddata, j);
2643           if (fromItem != NULL && toItem != NULL) {
2644             *toItem = *fromItem;
2645           }
2646         }
2647         itemPtr->startsAt = startsAt;
2648         (ddata.numItems)--;
2649         ddata.numLines = UpdateLineStarts (&ddata, item);
2650         SetPanelExtra ((PaneL) d, &ddata);
2651         if (ddata.autoAdjust) {
2652           AdjustDocScroll (d);
2653         }
2654       }
2655     }
2656   }
2657 }
2658 
2659 /*****************************************************************************
2660 *
2661 *   BulkAppendItem (d, numItems, proc, estLines, parFmt, colFmt, font)
2662 *       Populates a document in one step, assuming that the print function
2663 *       doesn't need individual data
2664 *
2665 *****************************************************************************/
2666 
2667 extern void BulkAppendItem (DoC d, Int2 numItems, DocPrntProc proc,
2668                             Int2 estLines, ParPtr parFmt,
2669                             ColPtr colFmt, FonT font)
2670 
2671 {
2672   ColXPtr    colXPtr;
2673   DocData    ddata;
2674   Int2       i;
2675   Int2       index;
2676   Int2       item;
2677   ItemPtr    itemPtr;
2678   Int2       leadHeight = 0;
2679   Int2       lineHeight = stdLineHeight;
2680   Int2       list;
2681   ListDPtr   listPtr;
2682   MasterPtr  masterPtr;
2683   Int2       numCols;
2684   Int2       numLists;
2685   ParData    parData;
2686   RecT       r;
2687 
2688   if (d != NULL && /* numItems <= 32767 && */ numItems > 0) {
2689     GetPanelExtra ((PaneL) d, &ddata);
2690     if (ddata.master == NULL) {
2691       ddata.master = (MasterPtr) MemNew (sizeof (MasterData));
2692       SetPanelExtra ((PaneL) d, &ddata);
2693     }
2694     numLists = (numItems / LISTSIZE) + 1;
2695     ObjectRect (d, &r);
2696     InsetRect (&r, 4, 4);
2697     if (numLists <= MAXLISTS && ddata.master != NULL) {
2698       masterPtr = ddata.master;
2699       for (list = 0; list < numLists; list++) {
2700         listPtr = masterPtr->list [list];
2701         if (listPtr == NULL) {
2702           masterPtr->list [list] = (ListDPtr) MemNew(sizeof(ListData));
2703           listPtr = masterPtr->list [list];
2704         }
2705       }
2706       if (colFmt == NULL) {
2707         colFmt = ddata.defaultColFmt;
2708       }
2709       if (colFmt == NULL) {
2710         defaultTable.pixWidth = r.right - r.left;
2711         defaultTable.charWidth = 80;
2712         colFmt = &defaultTable;
2713       }
2714       i = 0;
2715       while (! colFmt [i].last) {
2716         i++;
2717       }
2718       i++;
2719       numCols = i;
2720       colXPtr = CacheColFmt (d, colFmt);
2721       if (parFmt == NULL) {
2722         parFmt = ddata.defaultParFmt;
2723       }
2724       if (parFmt != NULL) {
2725         parData.openSpace = parFmt->openSpace;
2726         parData.keepWithNext = parFmt->keepWithNext;
2727         parData.keepTogether = parFmt->keepTogether;
2728         parData.newPage = parFmt->newPage;
2729         parData.tabStops = parFmt->tabStops;
2730         parData.minLines = MAX (parFmt->minLines, (Int2) 1);
2731         parData.minHeight = parFmt->minHeight;
2732       } else {
2733         parData.openSpace = TRUE;
2734         parData.keepWithNext = FALSE;
2735         parData.keepTogether = FALSE;
2736         parData.newPage = FALSE;
2737         parData.tabStops = FALSE;
2738         parData.minLines = 0;
2739         parData.minHeight = 0;
2740       }
2741       if (font == NULL) {
2742         font = ddata.defaultFont;
2743       }
2744       for (item = 0; item < numItems; item++) {
2745         list = (item / LISTSIZE);
2746         listPtr = masterPtr->list [list];
2747         if (listPtr != NULL) {
2748           index = (item % LISTSIZE);
2749           itemPtr = &(listPtr->items [index]);
2750           if (itemPtr != NULL) {
2751             itemPtr->prtProc = proc;
2752             itemPtr->dataPtr = NULL;
2753             itemPtr->text = NULL;
2754             itemPtr->cached = NULL;
2755             itemPtr->font = font;
2756             itemPtr->numRows = MAX (estLines, 1);
2757             itemPtr->numCols = numCols;
2758             itemPtr->colFmt = colXPtr;
2759             itemPtr->extra = NULL;
2760             itemPtr->startsAt = 0;
2761             itemPtr->openSpace = parData.openSpace;
2762             itemPtr->keepWithNext = parData.keepWithNext;
2763             itemPtr->keepTogether = parData.keepTogether;
2764             itemPtr->newPage = parData.newPage;
2765             itemPtr->tabStops = parData.tabStops;
2766             itemPtr->minLines = parData.minLines;
2767             itemPtr->minHeight = parData.minHeight;
2768             itemPtr->docOwnsData = FALSE;
2769             itemPtr->notCached = TRUE;
2770             itemPtr->neverCached = TRUE;
2771             if (item == 0) {
2772               UpdateItemHeights (itemPtr);
2773               lineHeight = itemPtr->lineHeight;
2774               leadHeight = itemPtr->leadHeight;
2775             }
2776             itemPtr->lineHeight = lineHeight;
2777             itemPtr->leadHeight = leadHeight;
2778           }
2779         }
2780       }
2781       ddata.numItems = numItems;
2782       ddata.numLines = UpdateLineStarts (&ddata, 0);
2783       SetPanelExtra ((PaneL) d, &ddata);
2784       if (ddata.upd != NULL) {
2785         ddata.upd ((DoC) d, 0, 0);
2786       }
2787       if (ddata.autoAdjust) {
2788         AdjustDocScroll (d);
2789       }
2790     }
2791   }
2792 }
2793 
2794 /*****************************************************************************
2795 *
2796 *   StdCache functions
2797 *       Simple binary tree cache
2798 *
2799 *****************************************************************************/
2800 
2801 extern void StdPutDocCache (DoC d, Int2 item, CharPtr text)
2802 
2803 {
2804   DocData  ddata;
2805   ItemPtr  itemPtr;
2806 
2807   if (d != NULL && item > 0) {
2808     GetPanelExtra ((PaneL) d, &ddata);
2809     itemPtr = GetItemPtr (&ddata, item - 1);
2810     if (itemPtr != NULL) {
2811       itemPtr->cached = MemFree (itemPtr->cached);
2812       itemPtr->cached = StringSave (text);
2813     }
2814   }
2815 }
2816 
2817 extern CharPtr StdGetDocCache (DoC d, Int2 item)
2818 
2819 {
2820   DocData  ddata;
2821   ItemPtr  itemPtr;
2822   CharPtr  text = NULL;
2823 
2824   if (d != NULL && item > 0) {
2825     GetPanelExtra ((PaneL) d, &ddata);
2826     itemPtr = GetItemPtr (&ddata, item - 1);
2827     if (itemPtr != NULL) {
2828       text = StringSave (itemPtr->cached);
2829     }
2830   }
2831   return text;
2832 }
2833 
2834 extern void StdResetDocCache (DoC d, Int2 from, Int2 to)
2835 
2836 {
2837   DocData  ddata;
2838   Int2     i;
2839   ItemPtr  itemPtr;
2840 
2841   GetPanelExtra ((PaneL) d, &ddata);
2842   for (i = 0; i < ddata.numItems; i++) {
2843     itemPtr = GetItemPtr (&ddata, i);
2844     if (itemPtr != NULL) {
2845       itemPtr->cached = MemFree (itemPtr->cached);
2846     }
2847   }
2848   SetPanelExtra ((PaneL) d, &ddata);
2849 }
2850 
2851 /*****************************************************************************
2852 *
2853 *   ResetDocument (d)
2854 *       Performs garbage collection on document data
2855 *
2856 *****************************************************************************/
2857 
2858 static void ResetDocument (PaneL d)
2859 
2860 {
2861   DocData    ddata;
2862   Int2       i;
2863   ItemPtr    itemPtr;
2864   MasterPtr  masterPtr;
2865   RecT       r;
2866 
2867   GetPanelExtra (d, &ddata);
2868   if (ddata.data != NULL && ddata.cleanup != NULL) {
2869     ddata.cleanup ((DoC) d, ddata.data);
2870   }
2871   if (ddata.upd != NULL) {
2872     ddata.upd ((DoC) d, 0, 0);
2873   }
2874   ObjectRect (d, &r);
2875   InsetRect (&r, 4, 4);
2876   for (i = 0; i < ddata.numItems; i++) {
2877     itemPtr = GetItemPtr (&ddata, i);
2878     if (itemPtr != NULL) {
2879       itemPtr->text = (CharPtr) MemFree (itemPtr->text);
2880       if (itemPtr->docOwnsData) {
2881         itemPtr->dataPtr = (Pointer) MemFree (itemPtr->dataPtr);
2882       } else {
2883         itemPtr->dataPtr = NULL;
2884       }
2885       itemPtr->extra = MemFree (itemPtr->extra);
2886       itemPtr->cached = MemFree (itemPtr->cached);
2887     }
2888   }
2889   if (ddata.master != NULL) {
2890     masterPtr = ddata.master;
2891     for (i = 0; i < MAXLISTS; i++) {
2892       masterPtr->list [i] = (ListDPtr) MemFree(masterPtr->list [i]);
2893     }
2894   }
2895   ddata.colFmts = ValNodeFreeData (ddata.colFmts);
2896   ddata.numItems = 0;
2897   ddata.numLines = 0;
2898   ddata.barmax = 0;
2899   ddata.pgUp = 0;
2900   ddata.pgDn = 0;
2901   ddata.master = (MasterPtr) MemFree (ddata.master);
2902   for (i = 0; i < MAXFONTS; i++) {
2903     fontHeights [i].font = NULL;
2904     fontHeights [i].height = 0;
2905   }
2906   ddata.data = NULL;
2907   ddata.cleanup = NULL;
2908   ddata.firstHighlightItem = 0;
2909   ddata.lastHighlightItem = 0;
2910   SetPanelExtra ((PaneL) d, &ddata);
2911 }
2912 
2913 /*****************************************************************************
2914 *
2915 *   NewDocument (d)
2916 *       Initialized document panel extra data
2917 *
2918 *****************************************************************************/
2919 
2920 static void NewDocument (DoC d)
2921 
2922 {
2923   DocData  ddata;
2924   Int2     i;
2925 
2926   ddata.numItems = 0;
2927   ddata.numLines = 0;
2928   ddata.barmax = 0;
2929   ddata.pgUp = 0;
2930   ddata.pgDn = 0;
2931   ddata.tabCount = 4;
2932   ddata.autoAdjust = TRUE;
2933   ddata.doc = d;
2934   ddata.master = NULL;
2935   ddata.draw = NULL;
2936   ddata.drawcell = NULL;
2937   ddata.pan = NULL;
2938   ddata.gray = NULL;
2939   ddata.invert = NULL;
2940   ddata.color = NULL;
2941   ddata.put = NULL;
2942   ddata.get = NULL;
2943   ddata.upd = NULL;
2944   ddata.data = NULL;
2945   ddata.cleanup = NULL;
2946   ddata.colFmts = NULL;
2947   for (i = 0; i < MAXFONTS; i++) {
2948     fontHeights [i].font = NULL;
2949     fontHeights [i].height = 0;
2950   }
2951   ddata.defaultParFmt = NULL;
2952   ddata.defaultColFmt = NULL;
2953   ddata.defaultFont = NULL;
2954   ddata.firstHighlightItem = 0;
2955   ddata.lastHighlightItem = 0;
2956   ddata.useRowsNotItems = FALSE;
2957   ddata.notify = NULL;
2958   SetPanelExtra ((PaneL) d, &ddata);
2959 }
2960 
2961 /*****************************************************************************
2962 *
2963 *   DocumentPanel (prnt, pixwidth, pixheight)
2964 *       Creates an empty document object
2965 *
2966 *****************************************************************************/
2967 
2968 extern DoC DocumentPanel (GrouP prnt, Int2 pixwidth, Int2 pixheight)
2969 
2970 {
2971   DoC  d;
2972   WindoW    tempPort;
2973 
2974   d = NULL;
2975   if (prnt != NULL) {
2976     tempPort = SavePort (prnt);
2977     d = (DoC) AutonomousPanel4 (prnt, pixwidth, pixheight, DrawDocument,
2978                                 DocumentScrlProc, NULL, sizeof (DocData),
2979                                 ResetDocument, NULL);
2980     if (d != NULL) {
2981       NewDocument (d);
2982     }
2983     RestorePort (tempPort);
2984   }
2985   return d;
2986 }
2987 
2988 /*****************************************************************************
2989 *
2990 *   SetDocProcs (d, click, drag, release, pan)
2991 *       Sets mouse callbacks for a document object
2992 *
2993 *****************************************************************************/
2994 
2995 extern void SetDocProcs (DoC d, DocClckProc click, DocClckProc drag,
2996                          DocClckProc release, DocPanProc pan)
2997 
2998 {
2999   DocData  ddata;
3000 
3001   if (d != NULL) {
3002     Nlm_SetPanelClick ((PaneL) d, (PnlClckProc) click, (PnlClckProc) drag,
3003                        NULL, (PnlClckProc) release);
3004     GetPanelExtra ((PaneL) d, &ddata);
3005     ddata.pan = pan;
3006     SetPanelExtra ((PaneL) d, &ddata);
3007   }
3008 }
3009 
3010 /*****************************************************************************
3011 *
3012 *   SetDocShade (d, draw, gray, invert, color)
3013 *       Sets draw callbacks for a document object
3014 *
3015 *****************************************************************************/
3016 
3017 extern void SetDocShade (DoC d, DocDrawProc draw, DocShadeProc gray,
3018                          DocShadeProc invert, DocShadeProc color)
3019 
3020 {
3021   DocData  ddata;
3022 
3023   if (d != NULL) {
3024     GetPanelExtra ((PaneL) d, &ddata);
3025     ddata.draw = draw;
3026     ddata.gray = gray;
3027     ddata.invert = invert;
3028     ddata.color = color;
3029     SetPanelExtra ((PaneL) d, &ddata);
3030   }
3031 }
3032 
3033 /*****************************************************************************
3034 *
3035 *   SetDocExtra (d, drawcell)
3036 *       Sets drawcell callback for a document object
3037 *
3038 *****************************************************************************/
3039 
3040 extern void SetDocExtra (DoC d, DocCellProc drawcell)
3041 
3042 {
3043   DocData  ddata;
3044 
3045   if (d != NULL) {
3046     GetPanelExtra ((PaneL) d, &ddata);
3047     ddata.drawcell = drawcell;
3048     SetPanelExtra ((PaneL) d, &ddata);
3049   }
3050 }
3051 
3052 /*****************************************************************************
3053 *
3054 *   SetDocCache (d, put, get, upd)
3055 *       Sets cache callbacks for a document object
3056 *
3057 *****************************************************************************/
3058 
3059 extern void SetDocCache (DoC d, DocPutProc put, DocGetProc get, DocUpdProc upd)
3060 
3061 {
3062   DocData  ddata;
3063 
3064   if (d != NULL) {
3065     GetPanelExtra ((PaneL) d, &ddata);
3066     ddata.put = put;
3067     ddata.get = get;
3068     ddata.upd = upd;
3069     SetPanelExtra ((PaneL) d, &ddata);
3070   }
3071 }
3072 
3073 /*****************************************************************************
3074 *
3075 *   SetDocData (d, data, cleanup)
3076 *       Attaches instance data to a document object
3077 *
3078 *****************************************************************************/
3079 
3080 void SetDocData (DoC d, VoidPtr data, DocFreeProc cleanup)
3081 
3082 {
3083   DocData  ddata;
3084 
3085   if (d != NULL) {
3086     GetPanelExtra ((PaneL) d, &ddata);
3087     ddata.data = data;
3088     ddata.cleanup = cleanup;
3089     SetPanelExtra ((PaneL) d, &ddata);
3090   }
3091 }
3092 
3093 /*****************************************************************************
3094 *
3095 *   GetDocData (d)
3096 *       Returns the instance data attached to a document object
3097 *
3098 *****************************************************************************/
3099 
3100 VoidPtr GetDocData (DoC d)
3101 
3102 {
3103   DocData  ddata;
3104 
3105   if (d != NULL) {
3106     GetPanelExtra ((PaneL) d, &ddata);
3107     return (ddata.data);
3108   } else {
3109     return NULL;
3110   }
3111 }
3112 
3113 /*****************************************************************************
3114 *
3115 *   GetDocParams (d, numItems, numLines)
3116 *       Returns document-specific information
3117 *
3118 *****************************************************************************/
3119 
3120 void GetDocParams4 (DoC d, Int2Ptr numItems, Int4Ptr numLines)
3121 
3122 {
3123   DocData  ddata;
3124   Int2     items;
3125   Int4     lines;
3126 
3127   items = 0;
3128   lines = 0;
3129   if (d != NULL) {
3130     GetPanelExtra ((PaneL) d, &ddata);
3131     items = ddata.numItems;
3132     lines = ddata.numLines;
3133   }
3134   if (numItems != NULL) {
3135     *numItems = items;
3136   }
3137   if (numLines != NULL) {
3138     *numLines = lines;
3139   }
3140 }
3141 
3142 void GetDocParams (DoC d, Int2Ptr numItems, Int2Ptr numLines)
3143 
3144 {
3145   Int4  lines;
3146 
3147   GetDocParams4 (d, numItems, &lines);
3148   if (numLines != NULL) {
3149     *numLines = (Int2) lines;
3150   }
3151 }
3152 
3153 /*****************************************************************************
3154 *
3155 *   GetItemParams (d, item, startsAt, numRows, numCols, lineHeight, data)
3156 *       Returns item-specific information
3157 *
3158 *****************************************************************************/
3159 
3160 void GetItemParams4 (DoC d, Int2 item, Int4Ptr startsAt, Int2Ptr numRows,
3161                      Int2Ptr numCols, Int2Ptr lineHeight, Pointer PNTR data)
3162 
3163 {
3164   Int2     cols;
3165   Int4     first;
3166   VoidPtr  dataPtr;
3167   DocData  ddata;
3168   Int2     height;
3169   ItemPtr  itemPtr;
3170   Int2     rows;
3171 
3172   cols = 0;
3173   first = 0;
3174   height = 0;
3175   rows = 0;
3176   dataPtr = NULL;
3177   if (d != NULL && item > 0) {
3178     GetPanelExtra ((PaneL) d, &ddata);
3179     itemPtr = GetItemPtr (&ddata, item - 1);
3180     if (itemPtr != NULL) {
3181       first = itemPtr->startsAt;
3182       rows = itemPtr->numRows;
3183       cols = itemPtr->numCols;
3184       height = itemPtr->lineHeight;
3185       dataPtr = itemPtr->dataPtr;
3186     }
3187   }
3188   if (startsAt != NULL) {
3189     *startsAt = first;
3190   }
3191   if (numRows != NULL) {
3192     *numRows = rows;
3193   }
3194   if (numCols != NULL) {
3195     *numCols = cols;
3196   }
3197   if (lineHeight != NULL) {
3198     *lineHeight = height;
3199   }
3200   if (data != NULL) {
3201     *data = dataPtr;
3202   }
3203 }
3204 
3205 void GetItemParams (DoC d, Int2 item, Int2Ptr startsAt, Int2Ptr numRows,
3206                     Int2Ptr numCols, Int2Ptr lineHeight, Pointer PNTR data)
3207 
3208 {
3209   Int4  first;
3210 
3211   GetItemParams4 (d, item, &first, numRows, numCols, lineHeight, data);
3212   if (startsAt != NULL) {
3213     *startsAt = (Int2) first;
3214   }
3215 }
3216 
3217 /*****************************************************************************
3218 *
3219 *   GetColParams (d, item, col, pixPos, pixWidth, pixInset, just)
3220 *       Returns column-specific information
3221 *
3222 *****************************************************************************/
3223 
3224 void GetColParams (DoC d, Int2 item, Int2 col, Int2Ptr pixPos,
3225                    Int2Ptr pixWidth, Int2Ptr pixInset, CharPtr just)
3226 
3227 {
3228   ColXPtr  colFmt;
3229   DocData  ddata;
3230   Int2     inset;
3231   ItemPtr  itemPtr;
3232   Char     jst;
3233   Int2     position;
3234   RecT     r;
3235   Int2     width;
3236 
3237   inset = 0;
3238   position = 0;
3239   width = 0;
3240   jst = 'l';
3241   if (d != NULL && item > 0 && col > 0) {
3242     GetPanelExtra ((PaneL) d, &ddata);
3243     ObjectRect (d, &r);
3244     InsetRect (&r, 4, 4);
3245     itemPtr = GetItemPtr (&ddata, item - 1);
3246     if (itemPtr != NULL && col <itemPtr->numCols + 1) {
3247       colFmt = itemPtr->colFmt;
3248       if (colFmt != NULL) {
3249         SetTablePixFormat (colFmt, r.left, itemPtr->numCols);
3250         position = colFmt [col - 1].position;
3251         width = colFmt [col - 1].pixWidth;
3252         inset = colFmt [col - 1].pixInset;
3253         jst = justToChar [colFmt [col - 1].just];
3254       }
3255     }
3256   }
3257   if (pixPos != NULL) {
3258     *pixPos = position;
3259   }
3260   if (pixWidth != NULL) {
3261     *pixWidth = width;
3262   }
3263   if (pixInset != NULL) {
3264     *pixInset = inset;
3265   }
3266   if (just != NULL) {
3267     *just = jst;
3268   }
3269 }
3270 
3271 /*****************************************************************************
3272 *
3273 *   MapDocPoint (d, pt, item, row, col, rct)
3274 *       Converts a mouse point to a item, row, and column positions
3275 *       within a document
3276 *
3277 *****************************************************************************/
3278 
3279 extern void MapDocPointEx (DoC d, PoinT pt, Int2Ptr item, Int2Ptr row, Int2Ptr col, RectPtr rct, Boolean prefer_first_match_col)
3280 
3281 {
3282   Int2     cl;
3283   ColXPtr  colFmt;
3284   DocData  ddata;
3285   Int2     firstItem;
3286   Int2     firstLine;
3287   Boolean  goOn, found;
3288   Int2     i;
3289   Int2     itemNum;
3290   ItemPtr  itemPtr;
3291   Int2     itm;
3292   Int2     leadHeight;
3293   Int2     lineHeight;
3294   Int2     numCols;
3295   Int2     numRows;
3296   Int4     off;
3297   RecT     q;
3298   RecT     r;
3299   RecT     rc;
3300   Int2     rw;
3301   BaR      sb;
3302 
3303   itm = 0;
3304   rw = 0;
3305   cl = 0;
3306   LoadRect (&rc, 0, 0, 0, 0);
3307   if (d != NULL) {
3308     GetPanelExtra ((PaneL) d, &ddata);
3309     ObjectRect (d, &r);
3310     InsetRect (&r, 4, 4);
3311     if (PtInRect (pt, &r)) {
3312       sb = GetSlateVScrollBar ((SlatE) d);
3313       if (sb != NULL) {
3314         goOn = TRUE;
3315         LoadRect (&q, r.left, r.top, r.right, r.top);
3316         off = GetBarValue (sb);
3317         itemNum = GetItemNum (&ddata, off);
3318         itemPtr = GetItemPtr (&ddata, itemNum);
3319         if (itemPtr != NULL) {
3320           firstLine = (Int2) (off - itemPtr->startsAt);
3321           firstItem = itemNum;
3322           while (goOn && itemNum < ddata.numItems) {
3323             itemPtr = GetItemPtr (&ddata, itemNum);
3324             if (itemPtr != NULL) {
3325               CacheIfNever (&ddata, itemNum + 1, itemPtr, &r, ddata.tabCount);
3326               SetTablePixFormat (itemPtr->colFmt, r.left, itemPtr->numCols);
3327               if (itemNum > firstItem) {
3328                 leadHeight = itemPtr->leadHeight;
3329               } else {
3330                 leadHeight = 0;
3331               }
3332               lineHeight = itemPtr->lineHeight;
3333               numRows = MIN (itemPtr->numRows - firstLine,
3334                              MAX ((r.bottom - q.top - leadHeight) / lineHeight, 0));
3335               numCols = itemPtr->numCols;
3336               colFmt = itemPtr->colFmt;
3337               q.bottom = q.top + leadHeight + lineHeight * numRows;
3338               if (PtInRect (pt, &q) && numRows > 0) {
3339                 goOn = FALSE;
3340                 itm = itemNum + 1;
3341                 if (pt.y <= q.top + leadHeight) {
3342                   rw = 0;
3343                 } else {
3344                   rw = firstLine + ((pt.y - q.top - leadHeight) / lineHeight) + 1;
3345                 }
3346                 if (numCols > 0 && colFmt != NULL) {
3347                   found = FALSE;
3348                   for (i = 0; i < numCols && !found; i++) {
3349                     if (pt.x >= colFmt [i].position &&
3350                         pt.x < colFmt [i].position + colFmt [i].pixWidth) {
3351                       cl = i + 1;
3352                       if (rw > 0) {
3353                         rc.left = colFmt [i].position;
3354                         rc.top = q.top + leadHeight + lineHeight * (rw - firstLine - 1);
3355                         rc.right = rc.left + colFmt [i].pixWidth;
3356                         rc.bottom = rc.top + lineHeight;
3357                       }
3358                       if (prefer_first_match_col) {
3359                         found = TRUE;
3360                       }
3361                     }
3362                   }
3363                 }
3364               } else {
3365                 q.top = q.bottom;
3366               }
3367               if (numRows < itemPtr->numRows - firstLine) {
3368                 goOn = FALSE;
3369               }
3370             }
3371             itemNum++;
3372             firstLine = 0;
3373           }
3374         }
3375       }
3376     }
3377   }
3378   if (item != NULL) {
3379     *item = itm;
3380   }
3381   if (row != NULL) {
3382     *row = rw;
3383   }
3384   if (col != NULL) {
3385     *col = cl;
3386   }
3387   if (rct != NULL) {
3388     *rct = rc;
3389   }
3390 }
3391 
3392 extern void MapDocPoint (DoC d, PoinT pt, Int2Ptr item, Int2Ptr row, Int2Ptr col, RectPtr rct)
3393 {
3394   MapDocPointEx (d, pt, item, row, col, rct, FALSE);
3395 }
3396 
3397 /*****************************************************************************
3398 *
3399 *   GetDocText (d, item, row, col)
3400 *       Returns a string with text from a document.  If item, row, or col
3401 *       parameters are 0, text is taken from any item, row, or column,
3402 *       respectively.  The string must be freed by the application
3403 *
3404 *****************************************************************************/
3405 
3406 extern CharPtr GetDocText (DoC d, Int2 item, Int2 row, Int2 col)
3407 
3408 {
3409   ByteStorePtr  bsp;
3410   Char          ch;
3411   Int2          cl;
3412   DocData       ddata;
3413   Int2          i;
3414   ItemData      itemData;
3415   ItemPtr       itemPtr;
3416   Int2          k;
3417   Int2          num;
3418   CharPtr       ptr;
3419   RecT          r;
3420   Int2          rw;
3421   Int2          start;
3422   Int2          stop;
3423   CharPtr       text;
3424 
3425   text = NULL;
3426   if (d != NULL && item >= 0 && row >= 0 && col >= 0) {
3427     ObjectRect (d, &r);
3428     InsetRect (&r, 4, 4);
3429     GetPanelExtra ((PaneL) d, &ddata);
3430     if (ddata.numItems > 0) {
3431       bsp = BSNew (0);
3432       if (bsp != NULL) {
3433         if (item == 0) {
3434           start = 0;
3435           stop = ddata.numItems;
3436         } else if (item <= ddata.numItems) {
3437           start = item - 1;
3438           stop = item;
3439         } else {
3440           start = 0;
3441           stop = 0;
3442         }
3443         for (i = start; i < stop; i++) {
3444           itemPtr = GetItemPtr (&ddata, i);
3445           if (itemPtr != NULL) {
3446             itemData.text = NULL;
3447             itemData.prtProc = itemPtr->prtProc;
3448             itemData.dataPtr = itemPtr->dataPtr;
3449             itemData.font = itemPtr->font;
3450             itemData.extra = itemPtr->extra;
3451             itemData.openSpace = itemPtr->openSpace;
3452             itemData.tabStops = itemPtr->tabStops;
3453             itemData.numRows = itemPtr->numRows;
3454             itemData.numCols = itemPtr->numCols;
3455             itemData.minLines = itemPtr->minLines;
3456             itemData.minHeight = itemPtr->minHeight;
3457             itemData.colFmt = itemPtr->colFmt;
3458             SetTablePixFormat (itemData.colFmt, r.left, itemData.numCols);
3459             if (itemData.prtProc != NULL) {
3460               FormatText (&ddata, i + 1, &itemData, TRUE, ddata.tabCount);
3461               itemPtr->numRows = itemData.numRows;
3462               itemPtr->neverCached = itemData.neverCached;
3463               SetTablePixFormat (itemData.colFmt, r.left, itemData.numCols);
3464               text = itemData.text;
3465               if (text != NULL && *text != '\0' && itemData.colFmt != NULL) {
3466                 if (i > start && itemData.openSpace > 0 && item == 0) {
3467                   BSPutByte (bsp, (Int2) '\n');
3468                 }
3469                 rw = 0;
3470                 cl = 0;
3471                 ptr = text;
3472                 ch = *ptr;
3473                 while (ch != '\0') {
3474                   if (ch == '\n') {
3475                     if ((rw + 1 == row && col == 0) || row == 0) {
3476                       BSPutByte (bsp, (Int2) '\n');
3477                     }
3478                     cl = 0;
3479                     rw++;
3480                     ptr++;
3481                   } else if (ch == '\t') {
3482                     if ((rw + 1 == row || row == 0) && col == 0) {
3483                       BSPutByte (bsp, (Int2) '\t');
3484                     }
3485                     cl++;
3486                     ptr++;
3487                   } else {
3488                     num = 0;
3489                     while (ch != '\0' && ch != '\t' && ch != '\n') {
3490                       num++;
3491                       ch = ptr [num];
3492                     }
3493                     if (num > 0 && (cl +1 == col || col == 0) &&
3494                         (rw + 1 == row || row == 0)) {
3495                       for (k = 0; k < num; k++) {
3496                         BSPutByte (bsp, (Int2) ptr [k]);
3497                       }
3498                     }
3499                     ptr += num;
3500                   }
3501                   ch = *ptr;
3502                 }
3503               }
3504             }
3505             MemFree (itemData.text);
3506           }
3507         }
3508         text = (CharPtr) BSMerge(bsp, NULL);
3509         BSFree (bsp);
3510         ddata.numLines = UpdateLineStarts (&ddata, start);
3511         SetPanelExtra ((PaneL) d, &ddata);
3512       }
3513     }
3514   }
3515   return text;
3516 }
3517 
3518 /*****************************************************************************
3519 *
3520 *   ItemIsVisible (d, item, top, bottom, firstLine)
3521 *       Finds the visible region of an item in a document
3522 *
3523 *****************************************************************************/
3524 
3525 extern Boolean ItemIsVisible (DoC d, Int2 item, Int2Ptr top,
3526                               Int2Ptr bottom, Int2Ptr firstLine)
3527 
3528 {
3529   DocData  ddata;
3530   Int2     firstItem;
3531   Int2     fstLine;
3532   Boolean  goOn;
3533   Int2     itemNum;
3534   ItemPtr  itemPtr;
3535   Int2     leadHeight;
3536   Int2     lineHeight;
3537   Int2     numRows;
3538   Int4     off;
3539   RecT     r;
3540   RecT     rct;
3541   Boolean  rsult;
3542   BaR      sb;
3543 
3544   rsult = FALSE;
3545   if (top != NULL) {
3546     *top = 0;
3547   }
3548   if (bottom != NULL) {
3549     *bottom = 0;
3550   }
3551   if (firstLine != NULL) {
3552    *firstLine = 0;
3553   }
3554   if (d != NULL) {
3555     ObjectRect (d, &r);
3556     InsetRect (&r, 4, 4);
3557     GetPanelExtra ((PaneL) d, &ddata);
3558     sb = GetSlateVScrollBar ((SlatE) d);
3559     if (item > 0 && item <= ddata.numItems && sb != NULL) {
3560       item--;
3561       goOn = TRUE;
3562       LoadRect (&rct, r.left, r.top, r.right, r.top);
3563       off = GetBarValue (sb);
3564       itemNum = GetItemNum (&ddata, off);
3565       itemPtr = GetItemPtr (&ddata, itemNum);
3566       if (itemPtr != NULL) {
3567         fstLine = (Int2) (off - itemPtr->startsAt);
3568         firstItem = itemNum;
3569         lineHeight = 0;
3570         leadHeight = 0;
3571         numRows = 0;
3572         while (goOn && itemNum < ddata.numItems && itemNum <= item) {
3573           itemPtr = GetItemPtr (&ddata, itemNum);
3574           if (itemPtr != NULL) {
3575             CacheIfNever (&ddata, itemNum + 1, itemPtr, &r, ddata.tabCount);
3576             SetTablePixFormat (itemPtr->colFmt, r.left, itemPtr->numCols);
3577             if (itemNum > firstItem) {
3578               leadHeight = itemPtr->leadHeight;
3579             } else {
3580               leadHeight = 0;
3581             }
3582             lineHeight = itemPtr->lineHeight;
3583             rct.top += leadHeight;
3584             numRows = MIN (itemPtr->numRows - fstLine,
3585                            MAX ((r.bottom - rct.top) / lineHeight, 0));
3586             rct.bottom = rct.top + lineHeight * numRows;
3587             if (itemNum == item) {
3588               goOn = FALSE;
3589               if (numRows > 0) {
3590                 if (top != NULL) {
3591                   *top = rct.top;
3592                 }
3593                 if (bottom != NULL) {
3594                   *bottom = rct.bottom;
3595                 }
3596                 if (firstLine != NULL) {
3597                   *firstLine = fstLine;
3598                 }
3599                 rsult = TRUE;
3600               }
3601             } else {
3602               rct.top = rct.bottom;
3603             }
3604             if (numRows < itemPtr->numRows - fstLine) {
3605               goOn = FALSE;
3606             }
3607           }
3608           itemNum++;
3609           fstLine = 0;
3610         }
3611       }
3612     }
3613   }
3614   return rsult;
3615 }
3616 
3617 /*****************************************************************************
3618 *
3619 *   GetScrlParams (d, offset, firstShown, firstLine)
3620 *       Returns scroll-specific information
3621 *
3622 *****************************************************************************/
3623 
3624 extern Boolean GetScrlParams4 (DoC d, Int4Ptr offset,
3625                                Int2Ptr firstShown, Int2Ptr firstLine)
3626 
3627 {
3628   DocData  ddata;
3629   Int2     item;
3630   Int4     line;
3631   Int4     off;
3632   Boolean  rsult;
3633   BaR      sb;
3634 
3635   rsult = FALSE;
3636   off = 0;
3637   item = 0;
3638   line = 0;
3639   if (d != NULL) {
3640     GetPanelExtra ((PaneL) d, &ddata);
3641     sb = GetSlateVScrollBar ((SlatE) d);
3642     if (sb != NULL) {
3643       off = GetBarValue (sb);
3644       item = GetItemNum (&ddata, off);
3645       line = off - GetStartsAt (&ddata, item);
3646       rsult = TRUE;
3647     }
3648   }
3649   if (offset != NULL) {
3650     *offset = off;
3651   }
3652   if (firstShown != NULL) {
3653     *firstShown = item + 1;
3654   }
3655   if (firstLine != NULL) {
3656     *firstLine = (Int2) line;
3657   }
3658   return rsult;
3659 }
3660 
3661 extern void SetScrlParams4 (DoC d, Int4 offset)
3662 
3663 {
3664   BaR      sb;
3665 
3666   if (d != NULL) {
3667     sb = GetSlateVScrollBar ((SlatE) d);
3668     if (sb != NULL) {
3669       SetBarValue (sb, offset);
3670     }
3671   }
3672 }
3673 
3674 
3675 extern Boolean GetScrlParams (DoC d, Int2Ptr offset,
3676                               Int2Ptr firstShown, Int2Ptr firstLine)
3677 
3678 {
3679   Int4     off;
3680   Boolean  rsult;
3681 
3682   rsult = GetScrlParams4 (d, &off, firstShown, firstLine);
3683   if (offset != NULL) {
3684     *offset = (Int2) off;
3685   }
3686   return rsult;
3687 }
3688 
3689 /*****************************************************************************
3690 *
3691 *   RowIsVisible (d, item, row, top, bottom)
3692 *       Finds the visible region of a row in an item of a document
3693 *
3694 *****************************************************************************/
3695 
3696 extern Boolean RowIsVisible (DoC d, Int2 item, Int2 row,
3697                              Int2Ptr top, Int2Ptr bottom)
3698 
3699 {
3700   Int2     bt;
3701   Int2     first;
3702   Int2     from;
3703   Int2     lineHeight;
3704   Int2     numRows;
3705   RecT     r;
3706   Boolean  rsult;
3707   Int2     tmp;
3708   Int2     to;
3709   Int2     tp;
3710 
3711   rsult = FALSE;
3712   if (top != NULL) {
3713     *top = 0;
3714   }
3715   if (bottom != NULL) {
3716     *bottom = 0;
3717   }
3718   if (d != NULL && item > 0) {
3719     if (Enabled (d) && AllParentsEnabled (d) &&
3720         Visible (d) && AllParentsVisible (d)) {
3721       if (ItemIsVisible (d, item, &tp, &bt, &first)) {
3722         ObjectRect (d, &r);
3723         InsetRect (&r, 4, 4);
3724         GetItemParams (d, item, NULL, &numRows, NULL, &lineHeight, NULL);
3725         from = MIN (row, numRows);
3726         to = MIN (row, numRows);
3727         first++;
3728         if (from > to) {
3729           tmp = from;
3730           from = to;
3731           to = tmp;
3732         }
3733         if (to >= first) {
3734           while (from > first) {
3735             tp += lineHeight;
3736             first++;
3737           }
3738           bt = tp;
3739           while (to >= from) {
3740             bt += lineHeight;
3741             from++;
3742           }
3743           if (tp >= r.top && tp <= r.bottom &&
3744               bt >= r.top && bt <= r.bottom) {
3745             if (top != NULL) {
3746               *top = tp;
3747             }
3748             if (bottom != NULL) {
3749               *bottom = bt;
3750             }
3751             rsult = TRUE;
3752           }
3753         }
3754       }
3755     }
3756   }
3757   return rsult;
3758 }
3759 
3760 /*****************************************************************************
3761 *
3762 *   InvalDocRows (d, item, from, to)
3763 *       Invalidates rows in a document
3764 *
3765 *****************************************************************************/
3766 
3767 extern void InvalDocRows (DoC d, Int2 item, Int2 from, Int2 to)
3768 
3769 {
3770   Int2    bottom;
3771   Int2    first;
3772   Int2    lineHeight;
3773   Int2    numRows;
3774   RecT    r;
3775   WindoW  tempPort;
3776   Int2    tmp;
3777   Int2    top;
3778 
3779   if (d != NULL) {
3780     if (Enabled (d) && AllParentsEnabled (d) &&
3781         Visible (d) && AllParentsVisible (d)) {
3782       if (item > 0 && from >= 0 && to >= 0) {
3783         if (ItemIsVisible (d, item, &top, &bottom, &first)) {
3784           ObjectRect (d, &r);
3785           InsetRect (&r, 4, 4);
3786           GetItemParams (d, item, NULL, &numRows, NULL, &lineHeight, NULL);
3787           from = MIN (from, numRows);
3788           to = MIN (to, numRows);
3789           first++;
3790           if (from > to) {
3791             tmp = from;
3792             from = to;
3793             to = tmp;
3794           }
3795           if (to >= first) {
3796             while (from > first) {
3797               top += lineHeight;
3798               first++;
3799             }
3800             bottom = top;
3801             while (to >= from) {
3802               bottom += lineHeight;
3803               from++;
3804             }
3805             if (top >= r.top && top <= r.bottom &&
3806                 bottom >= r.top && bottom <= r.bottom) {
3807               r.top = top;
3808               r.bottom = bottom;
3809               tempPort = SavePort (d);
3810               Select (d);
3811               InsetRect (&r, -1, -1);
3812               InvalRect (&r);
3813               RestorePort (tempPort);
3814             }
3815           }
3816         }
3817       } else if (item == 0) {
3818         tempPort = SavePort (d);
3819         Select (d);
3820         ObjectRect (d, &r);
3821         InsetRect (&r, 3, 3);
3822         InvalRect (&r);
3823         RestorePort (tempPort);
3824       }
3825     }
3826   }
3827 }
3828 
3829 /*****************************************************************************
3830 *
3831 *   InvalDocCols (d, item, from, to)
3832 *       Invalidates columns in a document
3833 *
3834 *****************************************************************************/
3835 
3836 extern void InvalDocCols (DoC d, Int2 item, Int2 from, Int2 to)
3837 
3838 {
3839   Int2     bottom;
3840   ColXPtr  colFmt;
3841   DocData  ddata;
3842   ItemPtr  itemPtr;
3843   Int2     numCols;
3844   RecT     r;
3845   WindoW   tempPort;
3846   Int2     tmp;
3847   Int2     top;
3848 
3849   if (d != NULL) {
3850     if (Enabled (d) && AllParentsEnabled (d) &&
3851         Visible (d) && AllParentsVisible (d)) {
3852       if (item > 0 && from >= 0 && to >= 0) {
3853         if (ItemIsVisible (d, item, &top, &bottom, NULL)) {
3854           GetPanelExtra ((PaneL) d, &ddata);
3855           itemPtr = GetItemPtr (&ddata, item - 1);
3856           if (itemPtr == NULL) return;
3857           colFmt = itemPtr->colFmt;
3858           if (colFmt == NULL) return;
3859           ObjectRect (d, &r);
3860           InsetRect (&r, 4, 4);
3861           numCols = itemPtr->numCols;
3862           from = MIN (from, numCols);
3863           to = MIN (to, numCols);
3864           if (from > to) {
3865             tmp = from;
3866             from = to;
3867             to = tmp;
3868           }
3869           if (from > 0) {
3870             from--;
3871           }
3872           if (to > 0 && to <= numCols) {
3873             to--;
3874           }
3875           if (from >= 0 && from < numCols && to >= 0 && to < numCols) {
3876             r.left = colFmt [from].position;
3877             r.right = colFmt [to].position + colFmt [to].pixWidth;
3878             if (top >= r.top && top <= r.bottom &&
3879                 bottom >= r.top && bottom <= r.bottom) {
3880               r.top = top;
3881               r.bottom = bottom;
3882               tempPort = SavePort (d);
3883               Select (d);
3884               InsetRect (&r, -1, -1);
3885               InvalRect (&r);
3886               RestorePort (tempPort);
3887             }
3888           }
3889         }
3890       } else if (item == 0) {
3891         tempPort = SavePort (d);
3892         Select (d);
3893         ObjectRect (d, &r);
3894         InsetRect (&r, 3, 3);
3895         InvalRect (&r);
3896         RestorePort (tempPort);
3897       }
3898     }
3899   }
3900 }
3901 
3902 /*****************************************************************************
3903 *
3904 *   InvalDocument (d)
3905 *       Invalidates visible area of a document
3906 *
3907 *****************************************************************************/
3908 
3909 extern void InvalDocument (DoC d)
3910 
3911 {
3912   InvalDocRows (d, 0, 0, 0);
3913 }
3914 
3915 /*****************************************************************************
3916 *
3917 *   UpdateDocument (d, from, to)
3918 *       Invalidates and updates items in a document
3919 *
3920 *****************************************************************************/
3921 
3922 extern void UpdateDocument (DoC d, Int2 from, Int2 to)
3923 
3924 {
3925   Int2     bottom;
3926   Boolean  botvis;
3927   DocData  ddata;
3928   Int2     item;
3929   ItemPtr  itemPtr;
3930   Int2     last;
3931   Int4     line;
3932   Int4     off;
3933   RecT     r;
3934   RecT     s;
3935   BaR      sb;
3936   Int2     start;
3937   Int2     stop;
3938   Int2     swap;
3939   WindoW   tempPort;
3940   Int2     top;
3941   Boolean  topvis;
3942   Int2     vis;
3943 
3944   if (d != NULL && from >= 0 && to >= 0) {
3945     GetPanelExtra ((PaneL) d, &ddata);
3946     if (from == 0 || from > ddata.numItems) {
3947       start = 0;
3948       from = 0;
3949     } else {
3950       start = from - 1;
3951     }
3952     if (to == 0 || to > ddata.numItems) {
3953       stop = ddata.numItems;
3954       to = ddata.numItems;
3955     } else {
3956       stop = to;
3957     }
3958     for (item = start; item < stop; item++) {
3959       itemPtr = GetItemPtr (&ddata,item);
3960       if (itemPtr != NULL) {
3961         itemPtr->text = (CharPtr) MemFree (itemPtr->text);
3962         itemPtr->notCached = TRUE;
3963         itemPtr->neverCached = TRUE;
3964         itemPtr->cached = (CharPtr) MemFree (itemPtr->cached);
3965       }
3966     }
3967     if (ddata.upd != NULL) {
3968       ddata.upd (d, MIN (from, to), MAX (from, to));
3969     }
3970     if (Enabled (d) && AllParentsEnabled (d) &&
3971         Visible (d) && AllParentsVisible (d)) {
3972       tempPort = SavePort (d);
3973       ObjectRect (d, &r);
3974       InsetRect (&r, 4, 4);
3975       Select (d);
3976       if (from > to && from != 0 && to != ddata.numItems) {
3977         swap = from;
3978         from = to;
3979         to = swap;
3980       }
3981       topvis = FALSE;
3982       botvis = FALSE;
3983       if (from > 0 && from <= ddata.numItems) {
3984         topvis = ItemIsVisible (d, from, &top, NULL, NULL);
3985         if (topvis) {
3986           r.top = top;
3987         }
3988       } else {
3989         topvis = TRUE;
3990       }
3991       if (to > 0 && to <= ddata.numItems) {
3992         botvis = ItemIsVisible (d, to, NULL, &bottom, NULL);
3993         if (botvis) {
3994           r.bottom = bottom;
3995         }
3996       } else {
3997         botvis = TRUE;
3998       }
3999       if (topvis || botvis) {
4000         InsetRect (&r, -1, -1);
4001         InvalRect (&r);
4002       } else {
4003         ObjectRect (d, &s);
4004         InsetRect (&s, 4, 4);
4005         sb = GetSlateVScrollBar ((SlatE) d);
4006         off = GetBarValue (sb);
4007         item = GetItemNum (&ddata, off);
4008         line = (Int2) (off - GetStartsAt (&ddata, item));
4009         vis = VisLinesBelow (&ddata, &s, item, line, NULL, NULL);
4010         last = GetItemNum (&ddata, off + vis - 1);
4011         if (item >= stop || last < start) {
4012         } else {
4013           InsetRect (&r, -1, -1);
4014           InvalRect (&r);
4015         }
4016       }
4017       RestorePort (tempPort);
4018     }
4019     AdjustDocScroll (d);
4020   }
4021 }
4022 
4023 /*****************************************************************************
4024 *
4025 *   SaveTableItem (itemPtr, f, tabStops, tabCount)
4026 *       Reformats and saves an item to a file
4027 *
4028 *****************************************************************************/
4029 
4030 static void SaveTableItem (ItemPtr itemPtr, FILE *f,
4031                            Boolean tabStops, Int2 tabCount)
4032 
4033 {
4034   Char     ch;
4035   Int2     col;
4036   ColXPtr  colFmt;
4037   Int2     i;
4038   Int2     insetLeft;
4039   Int2     insetRight;
4040   Char     just;
4041   Int2     next;
4042   Int2     num;
4043   Int2     pos;
4044   CharPtr  ptr;
4045   Int2     row;
4046   CharPtr  text;
4047 
4048   if (itemPtr != NULL && f != NULL) {
4049     text = itemPtr->text;
4050     colFmt = itemPtr->colFmt;
4051     if (text != NULL && *text != '\0' && colFmt != NULL) {
4052       pos = 0;
4053       row = 0;
4054       col = 0;
4055       ptr = text;
4056       ch = *ptr;
4057       while (ch != '\0') {
4058         if (ch == '\n') {
4059           col = 0;
4060           row++;
4061           ptr++;
4062           pos = 0;
4063           fputc ('\n', f);
4064         } else if (ch == '\t' && (! tabStops)) {
4065           col++;
4066           ptr++;
4067         } else  {
4068           num = 0;
4069           while (ch != '\0' && (ch != '\t' || tabStops) && ch != '\n') {
4070             num++;
4071             ch = ptr [num];
4072           }
4073           if (num > 0 && col < itemPtr->numCols) {
4074             just = justToChar [colFmt [col].just];
4075             if (just == 'c') {
4076               insetLeft = colFmt [col].charInset;
4077               insetRight = colFmt [col].charInset;
4078             } else if (just == 'l') {
4079               insetLeft = colFmt [col].charInset;
4080               insetRight = 0;
4081             } else if (just == 'r') {
4082               insetLeft = 0;
4083               insetRight = colFmt [col].charInset;
4084             } else {
4085               insetLeft = 0;
4086               insetRight = 0;
4087             }
4088             next = colFmt [col].position + insetLeft;
4089             if (tabCount > 0) {
4090               while (num > 0 && *ptr == '\t') {
4091                 num--;
4092                 ptr++;
4093                 next += tabCount;
4094               }
4095             }
4096             while (pos < next) {
4097               fputc (' ', f);
4098               pos++;
4099             }
4100             if (just == 'r') {
4101               next = colFmt [col].position + colFmt [col].charWidth -
4102                      insetRight - num;
4103               while (pos < next) {
4104                 fputc (' ', f);
4105                 pos++;
4106               }
4107             } else if (just == 'c') {
4108               next = colFmt [col].position + (colFmt [col].charWidth -
4109                      insetRight - num) / 2;
4110               while (pos < next) {
4111                 fputc (' ', f);
4112                 pos++;
4113               }
4114             }
4115             for (i = 0; i < num; i++) {
4116               fputc (ptr [i], f);
4117               pos++;
4118             }
4119           }
4120           ptr += num;
4121         }
4122         ch = *ptr;
4123       }
4124     }
4125   }
4126 }
4127 
4128 /*****************************************************************************
4129 *
4130 *   SaveDocument (d, f)
4131 *       Saves all document items to a file
4132 *
4133 *****************************************************************************/
4134 
4135 extern void SaveDocument (DoC d, FILE *f)
4136 
4137 {
4138   DocData   ddata;
4139   Int2      i;
4140   ItemData  itemData;
4141   ItemPtr   itemPtr;
4142 
4143   if (d != NULL && f != NULL) {
4144     GetPanelExtra ((PaneL) d, &ddata);
4145     ddata.put = NULL;
4146     ddata.get = NULL;
4147     ddata.upd = NULL;
4148     for (i = 0; i < ddata.numItems; i++) {
4149       itemPtr = GetItemPtr (&ddata, i);
4150       if (itemPtr != NULL) {
4151         itemData.text = NULL;
4152         itemData.cached = NULL;
4153         itemData.prtProc = itemPtr->prtProc;
4154         itemData.dataPtr = itemPtr->dataPtr;
4155         itemData.font = itemPtr->font;
4156         itemData.extra = itemPtr->extra;
4157         itemData.openSpace = itemPtr->openSpace;
4158         itemData.tabStops = itemPtr->tabStops;
4159         itemData.numRows = itemPtr->numRows;
4160         itemData.numCols = itemPtr->numCols;
4161         itemData.minLines = itemPtr->minLines;
4162         itemData.minHeight = itemPtr->minHeight;
4163         itemData.colFmt = itemPtr->colFmt;
4164         SetTableCharFormat (itemData.colFmt, itemData.numCols);
4165         if (itemData.prtProc != NULL) {
4166           FormatText (&ddata, i + 1, &itemData, FALSE, ddata.tabCount);
4167           SetTableCharFormat (itemData.colFmt, itemData.numCols);
4168           if (i > 0 && itemData.openSpace > 0) {
4169             fputc ('\n', f);
4170           }
4171           SaveTableItem (&itemData, f,
4172                          (Boolean) (unsigned int) itemData.tabStops,
4173                          ddata.tabCount);
4174           MemFree (itemData.text);
4175         }
4176       }
4177     }
4178   }
4179 }
4180 
4181 /*****************************************************************************
4182 *
4183 *   SaveDocumentItem (d, f, item)
4184 *       Saves one document item to a file
4185 *
4186 *****************************************************************************/
4187 
4188 extern void SaveDocumentItem (DoC d, FILE *f, Int2 item)
4189 
4190 {
4191   DocData   ddata;
4192   ItemData  itemData;
4193   ItemPtr   itemPtr;
4194 
4195   if (d != NULL && f != NULL) {
4196     GetPanelExtra ((PaneL) d, &ddata);
4197     ddata.put = NULL;
4198     ddata.get = NULL;
4199     ddata.upd = NULL;
4200     if (item > 0 && item <= ddata.numItems) {
4201       itemPtr = GetItemPtr (&ddata, item - 1);
4202       if (itemPtr != NULL) {
4203         itemData.text = NULL;
4204         itemData.cached = NULL;
4205         itemData.prtProc = itemPtr->prtProc;
4206         itemData.dataPtr = itemPtr->dataPtr;
4207         itemData.font = itemPtr->font;
4208         itemData.extra = itemPtr->extra;
4209         itemData.openSpace = itemPtr->openSpace;
4210         itemData.tabStops = itemPtr->tabStops;
4211         itemData.numRows = itemPtr->numRows;
4212         itemData.numCols = itemPtr->numCols;
4213         itemData.minLines = itemPtr->minLines;
4214         itemData.minHeight = itemPtr->minHeight;
4215         itemData.colFmt = itemPtr->colFmt;
4216         SetTableCharFormat (itemData.colFmt, itemData.numCols);
4217         if (itemData.prtProc != NULL) {
4218           FormatText (&ddata, item, &itemData, FALSE, ddata.tabCount);
4219           SetTableCharFormat (itemData.colFmt, itemData.numCols);
4220           /*
4221           if (item > 1 && itemData.openSpace > 0) {
4222             fputc ('\n', f);
4223           }
4224           */
4225           SaveTableItem (&itemData, f,
4226                          (Boolean) (unsigned int) itemData.tabStops,
4227                          ddata.tabCount);
4228           MemFree (itemData.text);
4229         }
4230       }
4231     }
4232   }
4233 }
4234 
4235 /*****************************************************************************
4236 *
4237 *   PrintDocument (d)
4238 *       Reformats and sends a document to the printer
4239 *
4240 *****************************************************************************/
4241 
4242 #ifdef WIN_MOTIF
4243 extern CharPtr Nlm_XrmGetResource (const Char PNTR _resource);
4244 #endif
4245 
4246 extern void PrintDocument (DoC d)
4247 
4248 {
4249 #ifndef WIN_MOTIF
4250   DocData   ddata;
4251   Boolean   goOn;
4252   Int2      i;
4253   Int2      item;
4254   ItemPtr   itemPtr;
4255   ItemData  itemData;
4256   Int2      line;
4257   Boolean   newPage;
4258   Int2      pixels;
4259   RecT      r;
4260   RecT      rct;
4261   FloatHi   scale;
4262   Int2      visBelow;
4263   WindoW    w;
4264 
4265   if (d != NULL) {
4266     GetPanelExtra ((PaneL) d, &ddata);
4267     ddata.put = NULL;
4268     ddata.get = NULL;
4269     ddata.upd = NULL;
4270     if (ddata.numItems > 0) {
4271       ObjectRect (d, &rct);
4272       InsetRect (&rct, 4, 4);
4273       w = StartPrinting ();
4274       if (w != NULL) {
4275         for (i = 0; i < MAXFONTS; i++) {
4276           fontHeights [i].font = NULL;
4277           fontHeights [i].height = 0;
4278         }
4279         goOn = TRUE;
4280         pixels = 0;
4281         item = 0;
4282         newPage = TRUE;
4283         while (item < ddata.numItems && goOn) {
4284           if (newPage) {
4285             goOn = StartPage ();
4286             newPage = FALSE;
4287             PrintingRect (&r);
4288           }
4289           if (goOn) {
4290             itemPtr = GetItemPtr (&ddata, item);
4291             if (itemPtr != NULL) {
4292               itemData.text = NULL;
4293               itemData.cached = NULL;
4294               itemData.prtProc = itemPtr->prtProc;
4295               itemData.dataPtr = itemPtr->dataPtr;
4296               itemData.font = itemPtr->font;
4297               itemData.extra = itemPtr->extra;
4298               itemData.openSpace = itemPtr->openSpace;
4299               itemData.keepWithNext = itemPtr->keepWithNext;
4300               itemData.keepTogether = itemPtr->keepTogether;
4301               itemData.newPage = itemPtr->newPage;
4302               itemData.tabStops = itemPtr->tabStops;
4303               itemData.numRows = itemPtr->numRows;
4304               itemData.numCols = itemPtr->numCols;
4305               itemData.minLines = itemPtr->minLines;
4306               itemData.minHeight = itemPtr->minHeight;
4307               itemData.colFmt = (ColXPtr) MemNew (itemData.numCols * sizeof (ColXData));
4308               if (itemData.colFmt != NULL) {
4309                 MemCopy (itemData.colFmt, itemPtr->colFmt,
4310                          itemData.numCols * sizeof (ColXData));
4311                 for (i = 0; i < itemData.numCols; i++) {
4312                   if (itemData.colFmt [i].zeroWidth) {
4313                     itemData.colFmt [i].pixWidth = 0;
4314                   }
4315                 }
4316               }
4317               UpdateItemHeights (&itemData);
4318               scale = (FloatHi) (r.right - r.left) / (FloatHi) (rct.right - rct.left);
4319               for (i = 0; i < itemData.numCols; i++) {
4320                 itemData.colFmt [i].pixWidth = (Int2) (scale *
4321                                                (FloatHi) itemData.colFmt [i].pixWidth);
4322               }
4323               SetTablePixFormat (itemData.colFmt, r.left, itemData.numCols);
4324               if (itemData.prtProc != NULL) {
4325                 FormatText (&ddata, item + 1, &itemData, TRUE, ddata.tabCount);
4326                 SetTablePixFormat (itemData.colFmt, r.left, itemData.numCols);
4327                 if (pixels != 0) {
4328                   r.top += itemData.leadHeight;
4329                 }
4330                 visBelow = (r.bottom - r.top) / itemData.lineHeight;
4331                 if ((itemData.keepTogether && visBelow < itemData.numRows) ||
4332                     itemData.newPage) {
4333                   goOn = EndPage ();
4334                   if (goOn) {
4335                     goOn = StartPage ();
4336                   }
4337                   newPage = FALSE;
4338                   PrintingRect (&r);
4339                   visBelow = (r.bottom - r.top) / itemData.lineHeight;
4340                 }
4341                 line = 0;
4342                 while (visBelow + line < itemData.numRows && goOn) {
4343                   pixels = DrawTableItem (d, &ddata, &itemData, &r, item, line, NULL,
4344                                           NULL, NULL, TRUE, ddata.tabCount);
4345                   r.top += pixels;
4346                   line += visBelow;
4347                   goOn = EndPage ();
4348                   if (goOn) {
4349                     StartPage ();
4350                   }
4351                   newPage = FALSE;
4352                   PrintingRect (&r);
4353                   visBelow = (r.bottom - r.top) / itemData.lineHeight;
4354                 }
4355                 if (visBelow > 0 && goOn) {
4356                   pixels = DrawTableItem (d, &ddata, &itemData, &r, item, line, NULL,
4357                                           NULL, NULL, TRUE, ddata.tabCount);
4358                   r.top += pixels;
4359                 }
4360               }
4361               MemFree (itemData.text);
4362               MemFree (itemData.colFmt);
4363             }
4364           }
4365           item++;
4366           if (r.top >= r.bottom) {
4367             goOn = EndPage ();
4368             newPage = TRUE;
4369           }
4370         }
4371         if ((! newPage) && goOn) {
4372           goOn = EndPage ();
4373         }
4374         EndPrinting (w);
4375         for (i = 0; i < MAXFONTS; i++) {
4376           fontHeights [i].font = NULL;
4377           fontHeights [i].height = 0;
4378         }
4379       }
4380     }
4381   }
4382 #endif
4383 #ifdef WIN_MOTIF
4384   Char     cmmd [256];
4385   FILE     *f;
4386   Int2     len;
4387   CharPtr  printCmd;
4388   Char     str [PATH_MAX];
4389 
4390   if (d != NULL) {
4391     TmpNam (str);
4392     f = FileOpen (str, "w");
4393     if (f != NULL) {
4394       SaveDocument (d, f);
4395       FileClose (f);
4396       printCmd = Nlm_XrmGetResource ("printCommand");
4397       if (printCmd != NULL) {
4398         StringNCpy_0 (cmmd, printCmd, sizeof (cmmd) - 1);
4399       } else {
4400         StringCpy (cmmd, "lp -c");
4401       }
4402       MemFree (printCmd);
4403       len = (Int2) StringLen (cmmd);
4404       while (len > 0 && cmmd [len] == ' ') {
4405         cmmd [len] = '\0';
4406         len--;
4407       }
4408       StringCat (cmmd, " ");
4409       StringCat (cmmd, str);
4410       StringCat (cmmd, "; rm ");
4411       StringCat (cmmd, str);
4412       system (cmmd);
4413     } else {
4414       StringCpy (cmmd, "rm ");
4415       StringCat (cmmd, str);
4416       system (cmmd);
4417     }
4418   }
4419 #endif
4420 }
4421 
4422 /*****************************************************************************
4423 *
4424 *   displayTable
4425 *       Default column table for file display functions
4426 *
4427 *****************************************************************************/
4428 
4429 static ColData displayTable = {0, 0, 80, 0, NULL, 'l',
4430                                TRUE, FALSE, FALSE, FALSE, TRUE};
4431 
4432 /*****************************************************************************
4433 *
4434 *   GetChar (fp)
4435 *       Gets a single character from a file, returning '\0' on end of file
4436 *
4437 *****************************************************************************/
4438 
4439 static Char GetChar (FILE *fp)
4440 
4441 {
4442 #if (defined(OS_DOS) || defined (OS_NT))
4443   Int2  actual;
4444   Char  buf [32];
4445   Char  ch;
4446 
4447   ch = '\0';
4448   actual = (Int2) FileRead (buf, 1, 1, fp);
4449   if (actual > 0) {
4450     ch = buf [0];
4451   }
4452   return ch;
4453 #else
4454   int  ch;
4455 
4456   ch = fgetc (fp);
4457   if (ch == EOF) {
4458     ch = '\0';
4459   }
4460   return (Char) ch;
4461 #endif
4462 }
4463 
4464 /*****************************************************************************
4465 *
4466 *   DisplayFancy (d, file, parFmt, colFmt, font, tabStops)
4467 *       Uses a document to display a file, allowing paragraph and column
4468 *       formatting to be specified
4469 *
4470 *****************************************************************************/
4471 
4472 extern void DisplayFancy (DoC d, CharPtr file, ParPtr parFmt,
4473                           ColPtr colFmt, FonT font, Int2 tabStops)
4474 
4475 {
4476   Int2     actual;
4477   Char     ch;
4478   Int2     cnt;
4479   Int8     cntr;
4480   DocData  ddata;
4481   FILE     *fp;
4482   Int2     leftOver;
4483   ParData  para;
4484   RecT     r;
4485   WindoW   tempPort;
4486   CharPtr  text;
4487   CharPtr  txt;
4488 #ifdef WIN_MAC
4489   CharPtr  p;
4490   CharPtr  q;
4491 #endif
4492 #if (defined(OS_DOS) || defined (OS_NT))
4493   CharPtr  p;
4494   CharPtr  q;
4495 #endif
4496 
4497   if (d != NULL && file != NULL && file [0] != '\0') {
4498     GetPanelExtra ((PaneL) d, &ddata);
4499     ddata.tabCount = tabStops;
4500     SetPanelExtra ((PaneL) d, &ddata);
4501     if (parFmt == NULL) {
4502       parFmt = &para;
4503     }
4504     if (colFmt == NULL) {
4505       colFmt = &displayTable;
4506     }
4507     Reset (d);
4508     tempPort = SavePort (d);
4509     ObjectRect (d, &r);
4510     InsetRect (&r, 4, 4);
4511     displayTable.pixWidth = r.right - r.left;
4512     if (font == NULL) {
4513       font = systemFont;
4514     }
4515     text = (CharPtr) MemNew (24000);
4516     if (text != NULL) {
4517       fp = FileOpen (file, "r");
4518       if (fp != NULL) {
4519         leftOver = 0;
4520         cntr = FileLength (file);
4521         cnt = (Int2) MIN (cntr, 15000L);
4522         para.openSpace = FALSE;
4523         para.keepWithNext = FALSE;
4524         para.keepTogether = FALSE;
4525         para.newPage = FALSE;
4526         para.tabStops = TRUE;
4527         para.minLines = 0;
4528         para.minHeight = 0;
4529         while (cnt > 0 && cntr > 0) {
4530           txt = text + leftOver;
4531           actual = (Int2) FileRead (txt, 1, cnt, fp);
4532           if (actual > 0) {
4533             cnt = actual;
4534             txt [cnt] = '\0';
4535             ch = GetChar (fp);
4536             while (ch != '\0' && ch != '\n' && cnt < 15900) {
4537               txt [cnt] = ch;
4538               cnt++;
4539               ch = GetChar (fp);
4540             }
4541             while ((ch == '\n' || ch == '\r') && cnt < 15900) {
4542               txt [cnt] = ch;
4543               cnt++;
4544               ch = GetChar (fp);
4545             }
4546             txt [cnt] = '\0';
4547 #if (defined(OS_DOS) || defined (OS_NT))
4548             p = text;
4549             q = text;
4550             while (*p) {
4551               if (*p == '\r') {
4552                 p++;
4553               } else {
4554                 *q = *p;
4555                 p++;
4556                 q++;
4557               }
4558             }
4559             *q = '\0';
4560 #endif
4561 #ifdef WIN_MAC
4562             p = text;
4563             q = text;
4564             while (*p) {
4565               if (*p == '\n') {
4566                 *q = '\n';
4567                 p++;
4568                 q++;
4569                 if (*p == '\r') {
4570                   p++;
4571                 }
4572               } else if (*p == '\r') {
4573                 *q = '\n';
4574                 p++;
4575                 q++;
4576                 if (*p == '\n') {
4577                   p++;
4578                 }
4579               } else {
4580                 *q = *p;
4581                 p++;
4582                 q++;
4583               }
4584             }
4585             *q = '\0';
4586 #endif
4587             AppendText (d, text, parFmt, colFmt, font);
4588             leftOver = 1;
4589             text [0] = ch;
4590             cntr -= cnt;
4591             cnt = (Int2) MIN (cntr, 15000L);
4592           } else {
4593             cnt = 0;
4594             cntr = 0;
4595           }
4596         }
4597         FileClose (fp);
4598       }
4599       text = (CharPtr) MemFree (text);
4600     }
4601     if (Enabled (d) && AllParentsEnabled (d) &&
4602         Visible (d) && AllParentsVisible (d)) {
4603       ObjectRect (d, &r);
4604       InsetRect (&r, 3, 3);
4605       Select (d);
4606       InvalRect (&r);
4607     }
4608     if (! ddata.autoAdjust) {
4609       AdjustDocScroll (d);
4610     }
4611     RestorePort (tempPort);
4612   }
4613 }
4614 
4615 /*****************************************************************************
4616 *
4617 *   DisplayFile (d, file, font)
4618 *       Simple function to display a file in a document
4619 *
4620 *****************************************************************************/
4621 
4622 extern void DisplayFile (DoC d, CharPtr file, FonT font)
4623 
4624 {
4625   DisplayFancy (d, file, NULL, NULL, font, 4);
4626 }
4627 
4628 

source navigation ]   [ diff markup ]   [ identifier search ]   [ freetext search ]   [ file search ]  

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.