Jack Jansen | c982ef2 | 2001-02-15 22:56:41 +0000 | [diff] [blame] | 1 | /* |
| 2 | * WETabHooks.c |
| 3 | * |
| 4 | * WASTE TABS PACKAGE |
| 5 | * Hooks for adding tab support to WASTE |
| 6 | * |
| 7 | * Written by: |
| 8 | * Mark Alldritt (original code) |
| 9 | * Dan Crevier (line breaks) |
| 10 | * John Daub (maintenance) |
| 11 | * Jonathan Kew (variable-width tabs) |
| 12 | * Marco Piovanelli (?) |
| 13 | * Bert Seltzer (horizontal scrolling) |
| 14 | * |
| 15 | */ |
| 16 | |
| 17 | #include "WETabs.h" |
| 18 | #include "WETabHooks.h" |
| 19 | |
| 20 | #define FIXROUND(f) ((SInt16) (((f) + 0x00008000) >> 16)) |
| 21 | #define BSL(A, B) (((SInt32) (A)) << (B)) |
| 22 | |
| 23 | static const Point kOneToOneScaling = { 1, 1 } ; |
| 24 | |
| 25 | pascal void _WETabDrawText |
| 26 | ( |
| 27 | const char * pText, |
| 28 | SInt32 textLength, |
| 29 | Fixed slop, |
| 30 | JustStyleCode styleRunPosition, |
| 31 | WEReference we |
| 32 | ) |
| 33 | { |
| 34 | #pragma unused ( slop, styleRunPosition ) |
| 35 | |
| 36 | LongRect destRect; |
| 37 | SInt32 beginChar = 0; |
| 38 | SInt32 ii; |
| 39 | SInt16 tabWidth; |
| 40 | SInt16 destLeft; |
| 41 | Point penPos; |
| 42 | SInt16 tabSize = WEGetTabSize(we); |
| 43 | |
| 44 | WEGetDestRect(&destRect, we); |
| 45 | destLeft = (SInt16) destRect.left; |
| 46 | |
| 47 | for ( ii = 0; ii < textLength; ii++ ) |
| 48 | { |
| 49 | if (pText[ii] == '\t') |
| 50 | { |
| 51 | DrawText(pText, beginChar, ii - beginChar); |
| 52 | |
| 53 | /* advance the pen to the next tab stop */ |
| 54 | GetPen(&penPos); |
| 55 | tabWidth = tabSize - (penPos.h - destLeft) % tabSize; |
| 56 | MoveTo(penPos.h + tabWidth, penPos.v); |
| 57 | beginChar = ii + 1; |
| 58 | } |
| 59 | } /* for */ |
| 60 | |
| 61 | DrawText(pText, beginChar, textLength - beginChar); |
| 62 | } |
| 63 | |
| 64 | pascal SInt32 _WETabPixelToChar |
| 65 | ( |
| 66 | const char * pText, |
| 67 | SInt32 textLength, |
| 68 | Fixed slop, |
| 69 | Fixed *width, |
| 70 | WEEdge *edge, |
| 71 | JustStyleCode styleRunPosition, |
| 72 | Fixed hPos, |
| 73 | WEReference we |
| 74 | ) |
| 75 | { |
| 76 | SInt32 beginChar = 0; |
| 77 | SInt32 offset = 0; |
| 78 | SInt32 ii; |
| 79 | Fixed lastWidth; |
| 80 | Fixed tabWidth; |
| 81 | SInt16 tabSize = WEGetTabSize(we); |
| 82 | |
| 83 | /* loop through every character in the segment looking for tabs */ |
| 84 | for ( ii = 0; ii < textLength; ii++ ) |
| 85 | { |
| 86 | /* exit now if width has gone negative */ |
| 87 | /* (i.e., if we have found which glyph was hit) */ |
| 88 | if (*width <= 0) |
| 89 | { |
| 90 | break; |
| 91 | } |
| 92 | |
| 93 | /* tab found? */ |
| 94 | if (pText[ii] == '\t') |
| 95 | { |
| 96 | /* calculate the width of the sub-segment preceding the tab */ |
| 97 | lastWidth = *width; |
| 98 | offset += PixelToChar((char *)pText + beginChar, ii - beginChar, slop, |
| 99 | lastWidth, (Boolean *) edge, width, styleRunPosition, |
| 100 | kOneToOneScaling, kOneToOneScaling); |
| 101 | beginChar = ii + 1; |
| 102 | |
| 103 | /* hit point past sub-segment? */ |
| 104 | if (*width >= 0) |
| 105 | { |
| 106 | /* increment hPos by width of sub-segment preceding the tab */ |
| 107 | hPos += (lastWidth - *width); |
| 108 | |
| 109 | /* calculate the width of the tab "glyph" (as a Fixed value) */ |
| 110 | tabWidth = BSL(tabSize - FIXROUND(hPos) % tabSize, 16); |
| 111 | |
| 112 | /* increment hPos by width of tab character */ |
| 113 | hPos += tabWidth; |
| 114 | |
| 115 | /* hit point within tab glyph? */ |
| 116 | if (*width < tabWidth) |
| 117 | { |
| 118 | /* yes: determine which half of tab glyph was hit */ |
| 119 | if (*width > (tabWidth >> 1)) |
| 120 | { |
| 121 | *edge = kTrailingEdge; /* second (trailing) edge of tab */ |
| 122 | offset++; |
| 123 | } |
| 124 | else |
| 125 | { |
| 126 | *edge = kLeadingEdge; /* first (leading) edge of tab */ |
| 127 | } |
| 128 | |
| 129 | /* returning -1 (as Fixed) in width means we're finished */ |
| 130 | *width = 0xFFFF0000; |
| 131 | } |
| 132 | else |
| 133 | { |
| 134 | /* hit point is past tab: keep looping */ |
| 135 | offset++; |
| 136 | *width -= tabWidth; |
| 137 | } |
| 138 | } /* if (*width >= 0) */ |
| 139 | } /* if tab found */ |
| 140 | } /* for */ |
| 141 | |
| 142 | /* no more tabs in this segment: process the last sub-segment */ |
| 143 | if (*width >= 0) |
| 144 | { |
| 145 | lastWidth = *width; |
| 146 | offset += PixelToChar((char *)pText + beginChar, textLength - beginChar, slop, |
| 147 | lastWidth, (Boolean *) edge, width, styleRunPosition, |
| 148 | kOneToOneScaling, kOneToOneScaling); |
| 149 | } |
| 150 | |
| 151 | /* round width to nearest integer value */ |
| 152 | /* this is supposed to fix an incompatibility with the WorldScript Power Adapter */ |
| 153 | *width = (*width + 0x00008000) & 0xFFFF0000; |
| 154 | |
| 155 | return offset; |
| 156 | } |
| 157 | |
| 158 | pascal SInt16 _WETabCharToPixel |
| 159 | ( |
| 160 | const char * pText, |
| 161 | SInt32 textLength, |
| 162 | Fixed slop, |
| 163 | SInt32 offset, |
| 164 | SInt16 direction, |
| 165 | JustStyleCode styleRunPosition, |
| 166 | SInt16 hPos, |
| 167 | WEReference we |
| 168 | ) |
| 169 | { |
| 170 | LongRect destRect; |
| 171 | SInt32 beginChar = 0; |
| 172 | SInt32 ii; |
| 173 | SInt16 width; |
| 174 | SInt16 destLeft; |
| 175 | SInt16 totalWidth = 0; |
| 176 | SInt16 tabSize = WEGetTabSize(we); |
| 177 | |
| 178 | WEGetDestRect(&destRect, we); |
| 179 | destLeft = (SInt16) destRect.left; |
| 180 | |
| 181 | /* measure text up to offset, if offset is within this segment, |
| 182 | otherwise to textLength */ |
| 183 | if (offset > textLength) |
| 184 | { |
| 185 | offset = textLength; |
| 186 | } |
| 187 | |
| 188 | for ( ii = 0; ii < offset; ii++ ) |
| 189 | { |
| 190 | if (pText[ii] == '\t') |
| 191 | { |
| 192 | /* calculate the pixel width of the subsegment preceding the tab */ |
| 193 | width = TextWidth(pText, beginChar, ii - beginChar); |
| 194 | totalWidth += width; |
| 195 | hPos += width; |
| 196 | |
| 197 | /* calculate tab width */ |
| 198 | width = tabSize - (hPos - destLeft) % tabSize; |
| 199 | totalWidth += width; |
| 200 | hPos += width; |
| 201 | |
| 202 | /* go to next subsegment */ |
| 203 | beginChar = ii + 1; |
| 204 | } |
| 205 | } /* for */ |
| 206 | |
| 207 | /* calculate width of remaining characters */ |
| 208 | width = CharToPixel((char *)pText + beginChar, textLength - beginChar, slop, |
| 209 | offset - beginChar, direction, styleRunPosition, |
| 210 | kOneToOneScaling, kOneToOneScaling); |
| 211 | totalWidth += width; |
| 212 | |
| 213 | return totalWidth; |
| 214 | } |
| 215 | |
| 216 | pascal StyledLineBreakCode _WETabLineBreak |
| 217 | ( |
| 218 | const char * pText, |
| 219 | SInt32 textLength, |
| 220 | SInt32 textStart, |
| 221 | SInt32 textEnd, |
| 222 | Fixed *textWidth, |
| 223 | SInt32 *textOffset, |
| 224 | WEReference we |
| 225 | ) |
| 226 | { |
| 227 | LongRect destRect; |
| 228 | SInt32 beginChar = textStart; |
| 229 | SInt32 ii; |
| 230 | Fixed tabWidth; |
| 231 | SInt16 destWidth; |
| 232 | StyledLineBreakCode breakCode = smBreakOverflow; |
| 233 | SInt16 tabSize = WEGetTabSize(we); |
| 234 | |
| 235 | WEGetDestRect(&destRect, we); |
| 236 | destWidth = (SInt16) (destRect.right - destRect.left); |
| 237 | |
| 238 | for ( ii = textStart; ii < textEnd; ii++ ) |
| 239 | { |
| 240 | if (pText[ii] == 0x0D) |
| 241 | { |
| 242 | /* found a <return>, so stop looking ahead for tabs */ |
| 243 | ii++; |
| 244 | break; |
| 245 | } |
| 246 | if (pText[ii] == '\t') |
| 247 | { |
| 248 | /* do previous "segment" */ |
| 249 | breakCode = StyledLineBreak((char *)pText, textLength, beginChar, ii, 0, textWidth, textOffset); |
| 250 | if ((breakCode != smBreakOverflow) || (ii >= textLength)) |
| 251 | { |
| 252 | break; |
| 253 | } |
| 254 | beginChar = ii + 1; |
| 255 | |
| 256 | /* calculate tab width (as a Fixed value) */ |
| 257 | tabWidth = BSL(tabSize - (destWidth - FIXROUND(*textWidth)) % tabSize, 16); |
| 258 | |
| 259 | /* if tabWidth > pixelWidth we break in tab */ |
| 260 | /* don't move tab to next line */ |
| 261 | if (tabWidth > *textWidth) |
| 262 | { |
| 263 | breakCode = smBreakWord; |
| 264 | *textOffset = ii + 1; |
| 265 | break; |
| 266 | } |
| 267 | else |
| 268 | { |
| 269 | *textWidth -= tabWidth; |
| 270 | } |
| 271 | } |
| 272 | } /* for */ |
| 273 | |
| 274 | /* do last sub-segment */ |
| 275 | if ((ii - beginChar >= 0) && (breakCode == smBreakOverflow)) |
| 276 | { |
| 277 | breakCode = StyledLineBreak((char *)pText, textLength, beginChar, ii, 0, textWidth, textOffset); |
| 278 | } |
| 279 | |
| 280 | return breakCode; |
| 281 | } |