home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / utility / UTextBox.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  12.3 KB  |  364 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. //    UTextBox.cp
  20.  
  21. // Based on "The TextBox You've Always Wanted" by Bryan K. Ressler (Beaker) in develop #9
  22.  
  23. #ifdef PowerPlant_PCH
  24.     #include PowerPlant_PCH
  25. #endif
  26.  
  27. #include "UTextBox.h"
  28.  
  29. #include <Gestalt.h>
  30. #include <Fonts.h>
  31. #include <FixMath.h>
  32.  
  33. // ---------------------------------------------------------------------------
  34. //        Ñ UTextBox
  35. // ---------------------------------------------------------------------------
  36. //    Constructor
  37.  
  38. /*
  39. void
  40. UTextBox::UTextBox( void )
  41. {
  42.     long gestResult;
  43.  
  44.     ::Gestalt( gestaltFontMgrAttr, &gestResult );
  45.     hasTrueType = ( gestResult & gestaltOutlineFonts );
  46. }
  47. */
  48.  
  49. // ---------------------------------------------------------------------------
  50. //        Ñ TBLineHeight
  51. // ---------------------------------------------------------------------------
  52. //    Figures line height
  53. //
  54. // Input:    theText        the entire text that was given to the DrawTextBox call
  55. //            textLen        the length in bytes of the text
  56. //            lhCode        the line height code that was passed to DrawTextBox
  57. //            startY        VAR - we return the starting vertical pen location here
  58. //
  59. // Output:    returns the line height to use
  60. //
  61.  
  62. unsigned short
  63. UTextBox::TBLineHeight( Ptr theText, unsigned long textLen,
  64.                         Rect *wrapBox, short lhCode, short *startY )
  65. {
  66.     short            asc,desc;    /* Used in the OutlineMetrics calls */
  67.     FontInfo        fInfo;        /* The old-style font information record */
  68.     Point            frac;        /* The fraction for the TrueType calls */
  69.     unsigned short    lineHeight;    /* The return value */
  70.     Boolean            hasTrueType;
  71.     long            gestResult;
  72.  
  73.     ::Gestalt( gestaltFontMgrAttr, &gestResult );
  74.     hasTrueType = ( gestResult & gestaltOutlineFonts );
  75.  
  76.     ::GetFontInfo( &fInfo );
  77.     if (lhCode < 0) {
  78.         frac.h = frac.v = 1;
  79.         if ( hasTrueType && ::IsOutline(frac, frac) ) {
  80.             ::OutlineMetrics( (short)textLen, theText, frac, frac, &asc, &desc,
  81.                 nil, nil, nil );
  82.             lineHeight = MAXOF(fInfo.ascent, asc) + MAXOF(fInfo. descent,-desc) +
  83.                 fInfo.leading;
  84.             *startY = wrapBox->top + MAXOF(fInfo.ascent, asc);
  85.             *startY += fInfo.leading;
  86.         } else {
  87.             lineHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
  88.             *startY = wrapBox->top + fInfo.ascent + fInfo.leading;
  89.         }
  90.     } else if (lhCode == 0) {
  91.         lineHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
  92.         *startY = wrapBox->top + fInfo.ascent + fInfo.leading;
  93.     } else {
  94.         lineHeight = lhCode;
  95.         *startY = wrapBox->top + lhCode + fInfo.leading;
  96.     }
  97.  
  98.     return(lineHeight);
  99. }
  100.  
  101. // ---------------------------------------------------------------------------
  102. //        Ñ TBDraw
  103. // ---------------------------------------------------------------------------
  104. //    Draws a line with appropriate justification
  105. //
  106. // Input:    breakCode    the break code that was returned from StyledLineBreak
  107. //            lineStart    pointer to the beginning of the text for the current line
  108. //            lineBytes    the length in bytes of the the text for this line
  109. //            wrapBox        the box within which we're wrapping
  110. //            align        the text alignment as specified by the user
  111. //            curY        our current vertical pen coordinate
  112. //            boxWidth    the width of wrapBox (since DrawTextBox already calculated it)
  113. //
  114. // Output:    none (draws on the screen)
  115. //
  116.  
  117. void
  118. UTextBox::TBDraw( StyledLineBreakCode breakCode, Ptr lineStart,
  119.                 long lineBytes, Rect *wrapBox, short align, short curY, short boxWidth )
  120. {
  121.     unsigned long    blackLen;    /* Length of non-white characters */
  122.     short            slop;        /* Number of pixels of slop for full just */
  123.  
  124.     blackLen = ::VisibleLength( (Ptr)lineStart, lineBytes);
  125.     
  126.     if (align == ntbJustFull) {
  127.         slop = boxWidth - ::TextWidth(lineStart, 0, blackLen);
  128.         ::MoveTo(wrapBox->left, curY);
  129.         if (breakCode == smBreakOverflow ||
  130.             *(lineStart + (lineBytes - 1)) == kReturnChar)
  131.             align = ::GetSysDirection();
  132.         else
  133.             ::DrawJust( (Ptr)lineStart, blackLen, slop );
  134.     }
  135.  
  136.     switch(align) {
  137.         case teForceLeft:
  138.         case teJustLeft:
  139.             ::MoveTo(wrapBox->left, curY);
  140.             break;
  141.         case teJustRight:
  142.             ::MoveTo(wrapBox->right - TextWidth(lineStart, 0, blackLen), curY);
  143.             break;
  144.         case teJustCenter:
  145.             ::MoveTo(wrapBox->left + (boxWidth - ::TextWidth(lineStart, 0, blackLen)) / 2,
  146.                 curY);
  147.             break;
  148.     }
  149.     if (align != ntbJustFull)
  150.         ::DrawText(lineStart, 0, lineBytes);
  151. }
  152.  
  153. // ---------------------------------------------------------------------------
  154. //        Ñ DrawTextBox
  155. // ---------------------------------------------------------------------------
  156. //    Word-wraps text inside a given box
  157. //
  158. // Input:    theText        the text we need to wrap
  159. //            textLen        the length in bytes of the text
  160. //            wrapBox        the box within which we're wrapping
  161. //            align        the text alignment
  162. //                            teForceLeft, teFlushLeft    left justified
  163. //                            teJustCenter, teCenter        center justified
  164. //                            teJustRight, teFlushRight    right justified
  165. //                            ntbJustFull                    full justified
  166. //                            teJustLeft, teFlushDefault    system justified
  167. //            lhCode        the line height code that was passed to DrawTextBox
  168. //                            < 0        variable - based on tallest character
  169. //                            0        default - based on GetFontInfo
  170. //                            > 0        fixed - use lhCode as the line height
  171. //            endY        VAR - if non-nil, the vertical coord of the last line
  172. //            lhUsed        VAR - if non-nil, the line height used to draw the text
  173. //
  174. // Output:    returns the number of line drawn total (even if they drew outside of
  175. //            the boundries of wrapBox)
  176. //            
  177.  
  178. short
  179. UTextBox::DrawTextBox( Ptr theText, unsigned long textLen, Rect *wrapBox,
  180.                     short align, short lhCode, short *endY, short *lhUsed)
  181. {
  182.     StyledLineBreakCode    breakCode;        /* Returned code from StyledLineBreak */
  183.     Fixed                fixedMax;        /* boxWidth converted to fixed point */
  184.     Fixed                wrapWid;        /* Width to wrap to */
  185.     short                boxWidth;        /* Width of the wrapBox */
  186.     long                lineBytes;        /* Number of bytes in one line */
  187.     unsigned short        lineHeight;        /* Calculated line height */
  188.     short                curY;            /* Current vertical pen location */
  189.     unsigned short        lineCount;        /* Number of lines we've drawn */
  190.     long                textLeft;        /* Pointer to remaining bytes of text */
  191.     Ptr                    lineStart;        /* Pointer to beginning of a line */
  192.     Ptr                    textEnd;        /* Pointer to the end of input text */
  193.  
  194.     boxWidth = wrapBox->right - wrapBox->left;
  195.     fixedMax = ::Long2Fix((long)boxWidth);
  196.     if (align == teFlushDefault)
  197.         align = ::GetSysDirection();
  198.  
  199.     lineHeight = UTextBox::TBLineHeight(theText, textLen, wrapBox, lhCode, &curY);
  200.     lineCount = 0;
  201.     lineStart = theText;
  202.     textEnd = theText + textLen;
  203.     textLeft = textLen;
  204.     
  205.     do {
  206.         lineBytes = 1;
  207.         wrapWid = fixedMax;
  208.  
  209.         breakCode = ::StyledLineBreak( (Ptr)lineStart, textLeft, 0, textLeft, 0,
  210.                                     &wrapWid, &lineBytes );
  211.         
  212.         UTextBox::TBDraw(breakCode, lineStart, lineBytes, wrapBox, align, curY, boxWidth);
  213.         curY += lineHeight;
  214.         lineStart += lineBytes;
  215.         textLeft -= lineBytes;
  216.         lineCount++;
  217.         
  218.     } while (lineStart < textEnd);
  219.     
  220.     if (endY)
  221.         *endY = curY - lineHeight;
  222.     if (lhUsed)
  223.         *lhUsed = lineHeight;
  224.  
  225.     return(lineCount);
  226. }
  227.  
  228. // ---------------------------------------------------------------------------
  229. //        Ñ DrawTextBox
  230. // ---------------------------------------------------------------------------
  231. //    Word-wraps text inside a given box
  232. //
  233. // Input:    theText        the text we need to wrap
  234. //            textLen        the length in bytes of the text
  235. //            wrapBox        the box within which we're wrapping
  236. //            align        the text alignment
  237. //                            teForceLeft, teFlushLeft    left justified
  238. //                            teJustCenter, teCenter        center justified
  239. //                            teJustRight, teFlushRight    right justified
  240. //                            ntbJustFull                    full justified
  241. //                            teJustLeft, teFlushDefault    system justified
  242. //            lhCode        the line height code that was passed to DrawTextBox
  243. //                            < 0        variable - based on tallest character
  244. //                            0        default - based on GetFontInfo
  245. //                            > 0        fixed - use lhCode as the line height
  246. //
  247. //            
  248.  
  249. void
  250. UTextBox::DrawTextBox( Ptr theText, unsigned long textLen, Rect *wrapBox,
  251.                     short align, short lhCode )
  252. {
  253.     RgnHandle            oldClip;        /* Saved clipping region */
  254.     StyledLineBreakCode    breakCode;        /* Returned code from StyledLineBreak */
  255.     Fixed                fixedMax;        /* boxWidth converted to fixed point */
  256.     Fixed                wrapWid;        /* Width to wrap to */
  257.     short                boxWidth;        /* Width of the wrapBox */
  258.     long                lineBytes;        /* Number of bytes in one line */
  259.     unsigned short        lineHeight;        /* Calculated line height */
  260.     short                curY;            /* Current vertical pen location */
  261.     unsigned short        lineCount;        /* Number of lines we've drawn */
  262.     long                textLeft;        /* Pointer to remaining bytes of text */
  263.     Ptr                    lineStart;        /* Pointer to beginning of a line */
  264.     Ptr                    textEnd;        /* Pointer to the end of input text */
  265.  
  266.     ::GetClip((oldClip = ::NewRgn()));
  267.     ::ClipRect(wrapBox);
  268.     boxWidth = wrapBox->right - wrapBox->left;
  269.     fixedMax = ::Long2Fix((long)boxWidth);
  270.     if (align == teFlushDefault)
  271.         align = ::GetSysDirection();
  272.  
  273.     lineHeight = UTextBox::TBLineHeight(theText, textLen, wrapBox, lhCode, &curY);
  274.     lineCount = 0;
  275.     lineStart = theText;
  276.     textEnd = theText + textLen;
  277.     textLeft = textLen;
  278.     
  279.     do {
  280.         lineBytes = 1;
  281.         wrapWid = fixedMax;
  282.  
  283.         breakCode = ::StyledLineBreak( (Ptr)lineStart, textLeft, 0, textLeft, 0,
  284.                                     &wrapWid, &lineBytes );
  285.         
  286.         UTextBox::TBDraw(breakCode, lineStart, lineBytes, wrapBox, align, curY, boxWidth);
  287.         
  288.         curY += lineHeight;
  289.         lineStart += lineBytes;
  290.         textLeft -= lineBytes;
  291.         lineCount++;
  292.         
  293.     } while ((lineStart < textEnd) & ( curY <= (wrapBox->bottom + lineHeight) ));
  294.     
  295.     ::SetClip(oldClip);
  296.     ::DisposeRgn(oldClip);
  297.  
  298. }
  299.  
  300. // Hacked up, copied version of DrawTextBox. Returns the height needed for the lines
  301. // DESTROYS THE ORIGINAL STRING
  302. // pkc (6/6/96) added scan for '\n' to determine line breaks since StyledLineBreak doesn't
  303. // consider '\n' to be a line break.
  304. short UTextBox::TextBoxDialogHeight( Ptr theText, unsigned long textLen, Rect *wrapBox,
  305.                     short align, short lhCode)
  306. {
  307.     StyledLineBreakCode    breakCode;        /* Returned code from StyledLineBreak */
  308.     Fixed                fixedMax;        /* boxWidth converted to fixed point */
  309.     Fixed                wrapWid;        /* Width to wrap to */
  310.     short                boxWidth;        /* Width of the wrapBox */
  311.     long                lineBytes;        /* Number of bytes in one line */
  312.     unsigned short        lineHeight;        /* Calculated line height */
  313.     short                curY;            /* Current vertical pen location */
  314.     unsigned short        lineCount;        /* Number of lines we've drawn */
  315.     long                textLeft;        /* Pointer to remaining bytes of text */
  316.     Ptr                    lineStart;        /* Pointer to beginning of a line */
  317.     Ptr                    textEnd;        /* Pointer to the end of input text */
  318.     Ptr                    scanner;        /* Pointer to scan for '\n' */
  319.  
  320.     boxWidth = wrapBox->right - wrapBox->left;
  321.     fixedMax = ::Long2Fix((long)boxWidth);
  322.     if (align == teFlushDefault)
  323.         align = ::GetSysDirection();
  324.  
  325.     lineHeight = UTextBox::TBLineHeight(theText, textLen, wrapBox, lhCode, &curY);
  326.     lineCount = 0;
  327.     lineStart = theText;
  328.     textEnd = theText + textLen;
  329.     textLeft = textLen;
  330.     
  331.     // ÑÑÑ HACK
  332.     
  333.     for (int i=0; i< textLen; i++)
  334.     {
  335.         if (theText[i] == '/')
  336.             theText[i] = 'w';
  337.     }
  338.     do {
  339.         lineBytes = 1;
  340.         wrapWid = fixedMax;
  341.  
  342.         breakCode = ::StyledLineBreak( (Ptr)lineStart, textLeft, 0, textLeft, 0,
  343.                                     &wrapWid, &lineBytes );
  344.         // pkc (6/6/96) now scan for '\n' because StyledLineBreak doesn't take '\n' into account
  345.         scanner = lineStart;
  346.         while( *scanner != '\n' && scanner < textEnd )
  347.             ++scanner;
  348.         // pkc (6/6/96) move past '\n'
  349.         ++scanner;
  350.         // pkc (6/6/96) if there is a '\n' before where StyledLineBreak says that there should be
  351.         // a break, we should break at the '\n'
  352.         if( scanner < textEnd && scanner - lineStart < lineBytes )
  353.             lineBytes = scanner - lineStart;
  354.         curY += lineHeight;
  355.         lineStart += lineBytes;
  356.         textLeft -= lineBytes;
  357.         lineCount++;
  358.         
  359.     } while (lineStart < textEnd);
  360.     
  361.  
  362.     return(lineCount * lineHeight);
  363. }
  364.