| /* |
| * WETabHooks.c |
| * |
| * WASTE TABS PACKAGE |
| * Hooks for adding tab support to WASTE |
| * |
| * Written by: |
| * Mark Alldritt (original code) |
| * Dan Crevier (line breaks) |
| * John Daub (maintenance) |
| * Jonathan Kew (variable-width tabs) |
| * Marco Piovanelli (?) |
| * Bert Seltzer (horizontal scrolling) |
| * |
| */ |
| |
| #include "WETabs.h" |
| #include "WETabHooks.h" |
| |
| #define FIXROUND(f) ((SInt16) (((f) + 0x00008000) >> 16)) |
| #define BSL(A, B) (((SInt32) (A)) << (B)) |
| |
| static const Point kOneToOneScaling = { 1, 1 } ; |
| |
| pascal void _WETabDrawText |
| ( |
| const char * pText, |
| SInt32 textLength, |
| Fixed slop, |
| JustStyleCode styleRunPosition, |
| WEReference we |
| ) |
| { |
| #pragma unused ( slop, styleRunPosition ) |
| |
| LongRect destRect; |
| SInt32 beginChar = 0; |
| SInt32 ii; |
| SInt16 tabWidth; |
| SInt16 destLeft; |
| Point penPos; |
| SInt16 tabSize = WEGetTabSize(we); |
| |
| WEGetDestRect(&destRect, we); |
| destLeft = (SInt16) destRect.left; |
| |
| for ( ii = 0; ii < textLength; ii++ ) |
| { |
| if (pText[ii] == '\t') |
| { |
| DrawText(pText, beginChar, ii - beginChar); |
| |
| /* advance the pen to the next tab stop */ |
| GetPen(&penPos); |
| tabWidth = tabSize - (penPos.h - destLeft) % tabSize; |
| MoveTo(penPos.h + tabWidth, penPos.v); |
| beginChar = ii + 1; |
| } |
| } /* for */ |
| |
| DrawText(pText, beginChar, textLength - beginChar); |
| } |
| |
| pascal SInt32 _WETabPixelToChar |
| ( |
| const char * pText, |
| SInt32 textLength, |
| Fixed slop, |
| Fixed *width, |
| WEEdge *edge, |
| JustStyleCode styleRunPosition, |
| Fixed hPos, |
| WEReference we |
| ) |
| { |
| SInt32 beginChar = 0; |
| SInt32 offset = 0; |
| SInt32 ii; |
| Fixed lastWidth; |
| Fixed tabWidth; |
| SInt16 tabSize = WEGetTabSize(we); |
| |
| /* loop through every character in the segment looking for tabs */ |
| for ( ii = 0; ii < textLength; ii++ ) |
| { |
| /* exit now if width has gone negative */ |
| /* (i.e., if we have found which glyph was hit) */ |
| if (*width <= 0) |
| { |
| break; |
| } |
| |
| /* tab found? */ |
| if (pText[ii] == '\t') |
| { |
| /* calculate the width of the sub-segment preceding the tab */ |
| lastWidth = *width; |
| offset += PixelToChar((char *)pText + beginChar, ii - beginChar, slop, |
| lastWidth, (Boolean *) edge, width, styleRunPosition, |
| kOneToOneScaling, kOneToOneScaling); |
| beginChar = ii + 1; |
| |
| /* hit point past sub-segment? */ |
| if (*width >= 0) |
| { |
| /* increment hPos by width of sub-segment preceding the tab */ |
| hPos += (lastWidth - *width); |
| |
| /* calculate the width of the tab "glyph" (as a Fixed value) */ |
| tabWidth = BSL(tabSize - FIXROUND(hPos) % tabSize, 16); |
| |
| /* increment hPos by width of tab character */ |
| hPos += tabWidth; |
| |
| /* hit point within tab glyph? */ |
| if (*width < tabWidth) |
| { |
| /* yes: determine which half of tab glyph was hit */ |
| if (*width > (tabWidth >> 1)) |
| { |
| *edge = kTrailingEdge; /* second (trailing) edge of tab */ |
| offset++; |
| } |
| else |
| { |
| *edge = kLeadingEdge; /* first (leading) edge of tab */ |
| } |
| |
| /* returning -1 (as Fixed) in width means we're finished */ |
| *width = 0xFFFF0000; |
| } |
| else |
| { |
| /* hit point is past tab: keep looping */ |
| offset++; |
| *width -= tabWidth; |
| } |
| } /* if (*width >= 0) */ |
| } /* if tab found */ |
| } /* for */ |
| |
| /* no more tabs in this segment: process the last sub-segment */ |
| if (*width >= 0) |
| { |
| lastWidth = *width; |
| offset += PixelToChar((char *)pText + beginChar, textLength - beginChar, slop, |
| lastWidth, (Boolean *) edge, width, styleRunPosition, |
| kOneToOneScaling, kOneToOneScaling); |
| } |
| |
| /* round width to nearest integer value */ |
| /* this is supposed to fix an incompatibility with the WorldScript Power Adapter */ |
| *width = (*width + 0x00008000) & 0xFFFF0000; |
| |
| return offset; |
| } |
| |
| pascal SInt16 _WETabCharToPixel |
| ( |
| const char * pText, |
| SInt32 textLength, |
| Fixed slop, |
| SInt32 offset, |
| SInt16 direction, |
| JustStyleCode styleRunPosition, |
| SInt16 hPos, |
| WEReference we |
| ) |
| { |
| LongRect destRect; |
| SInt32 beginChar = 0; |
| SInt32 ii; |
| SInt16 width; |
| SInt16 destLeft; |
| SInt16 totalWidth = 0; |
| SInt16 tabSize = WEGetTabSize(we); |
| |
| WEGetDestRect(&destRect, we); |
| destLeft = (SInt16) destRect.left; |
| |
| /* measure text up to offset, if offset is within this segment, |
| otherwise to textLength */ |
| if (offset > textLength) |
| { |
| offset = textLength; |
| } |
| |
| for ( ii = 0; ii < offset; ii++ ) |
| { |
| if (pText[ii] == '\t') |
| { |
| /* calculate the pixel width of the subsegment preceding the tab */ |
| width = TextWidth(pText, beginChar, ii - beginChar); |
| totalWidth += width; |
| hPos += width; |
| |
| /* calculate tab width */ |
| width = tabSize - (hPos - destLeft) % tabSize; |
| totalWidth += width; |
| hPos += width; |
| |
| /* go to next subsegment */ |
| beginChar = ii + 1; |
| } |
| } /* for */ |
| |
| /* calculate width of remaining characters */ |
| width = CharToPixel((char *)pText + beginChar, textLength - beginChar, slop, |
| offset - beginChar, direction, styleRunPosition, |
| kOneToOneScaling, kOneToOneScaling); |
| totalWidth += width; |
| |
| return totalWidth; |
| } |
| |
| pascal StyledLineBreakCode _WETabLineBreak |
| ( |
| const char * pText, |
| SInt32 textLength, |
| SInt32 textStart, |
| SInt32 textEnd, |
| Fixed *textWidth, |
| SInt32 *textOffset, |
| WEReference we |
| ) |
| { |
| LongRect destRect; |
| SInt32 beginChar = textStart; |
| SInt32 ii; |
| Fixed tabWidth; |
| SInt16 destWidth; |
| StyledLineBreakCode breakCode = smBreakOverflow; |
| SInt16 tabSize = WEGetTabSize(we); |
| |
| WEGetDestRect(&destRect, we); |
| destWidth = (SInt16) (destRect.right - destRect.left); |
| |
| for ( ii = textStart; ii < textEnd; ii++ ) |
| { |
| if (pText[ii] == 0x0D) |
| { |
| /* found a <return>, so stop looking ahead for tabs */ |
| ii++; |
| break; |
| } |
| if (pText[ii] == '\t') |
| { |
| /* do previous "segment" */ |
| breakCode = StyledLineBreak((char *)pText, textLength, beginChar, ii, 0, textWidth, textOffset); |
| if ((breakCode != smBreakOverflow) || (ii >= textLength)) |
| { |
| break; |
| } |
| beginChar = ii + 1; |
| |
| /* calculate tab width (as a Fixed value) */ |
| tabWidth = BSL(tabSize - (destWidth - FIXROUND(*textWidth)) % tabSize, 16); |
| |
| /* if tabWidth > pixelWidth we break in tab */ |
| /* don't move tab to next line */ |
| if (tabWidth > *textWidth) |
| { |
| breakCode = smBreakWord; |
| *textOffset = ii + 1; |
| break; |
| } |
| else |
| { |
| *textWidth -= tabWidth; |
| } |
| } |
| } /* for */ |
| |
| /* do last sub-segment */ |
| if ((ii - beginChar >= 0) && (breakCode == smBreakOverflow)) |
| { |
| breakCode = StyledLineBreak((char *)pText, textLength, beginChar, ii, 0, textWidth, textOffset); |
| } |
| |
| return breakCode; |
| } |