static char* SpellCheck( int i, int language) { // on entry we will have passed over words which are KnownWord (including bases) or isInitialWord (all initials) // wordstarts from 1 ... wordCount is the incoming sentence words (original). We are processing the ith word here. char* word = wordStarts[i]; if (!*word) return NULL; if (!stricmp(word,loginID) || !stricmp(word,computerID)) return word; // dont change his/our name ever size_t len = strlen(word); if (len > 2 && word[len-2] == '\'') return word; // dont do anything with ' words // test for run togetherness like "talkabout fingers" int breakAt = SplitWord(word); if (breakAt > 0)// we found a split, insert 2nd word into word stream { char* tokens[3]; WORDP D = FindWord(word,breakAt,PRIMARY_CASE_ALLOWED); tokens[1] = D->word; tokens[2] = word+breakAt; ReplaceWords(i,1,2,tokens); fixedSpell = true; return NULL; } // now imagine partial runtogetherness, like "talkab out fingers" if (i < wordCount) { char tmp[MAX_WORD_SIZE]; strcpy(tmp,word); strcat(tmp,wordStarts[i+1]); breakAt = SplitWord(tmp); if (breakAt > 0) // replace words with the dual pair { char* tokens[3]; WORDP D = FindWord(tmp,breakAt,PRIMARY_CASE_ALLOWED); tokens[1] = D->word; tokens[2] = tmp+breakAt; ReplaceWords(i,2,2,tokens); fixedSpell = true; return NULL; } } // remove any nondigit characters repeated more than once. Dont do this earlier, we want substitutions to have a chance at it first. ammmmmmazing static char word1[MAX_WORD_SIZE]; char* ptr = word-1; char* ptr1 = word1; while (*++ptr) { *ptr1 = *ptr; while (ptr[1] == *ptr1 && ptr[2] == *ptr1 && (*ptr1 < '0' || *ptr1 > '9')) ++ptr; // skip double repeats ++ptr1; } *ptr1 = 0; if (FindCanonical(word1,0,true) && !IsUpperCase(*word1)) return word1; // this is a different form of a canonical word so its ok // now use word spell checker char* d = SpellFix(word,i,PART_OF_SPEECH,language); return (d) ? d : NULL; }
static char* SpellCheck(unsigned int i) { // on entry we will have passed over words which are KnownWord (including bases) or isInitialWord (all initials) // wordstarts from 1 ... wordCount is the incoming sentence words (original). We are processing the ith word here. char* word = wordStarts[i]; if (!*word) return NULL; if (!stricmp(word,loginID) || !stricmp(word,computerID)) return word; // dont change his/our name ever size_t len = strlen(word); if (len > 2 && word[len-2] == '\'') return word; // dont do anything with ' words // test for run togetherness like "talkabout fingers" int breakAt = SplitWord(word); if (breakAt > 0)// we found a split, insert 2nd word into word stream { ++wordCount; memmove(wordStarts+i+1,wordStarts+i,sizeof(char*) * (wordCount-i)); // open up a slot for a new word wordStarts[i+1] = reuseAllocation(wordStarts[i+1],wordStarts[i]+breakAt); // set this to the second word (shared from within 1st word) return FindWord(wordStarts[i],breakAt,PRIMARY_CASE_ALLOWED)->word; // 1st word gets replaced, we added valid word after } // now imagine partial runtogetherness, like "talkab out fingers" if (i < wordCount) { char tmp[MAX_WORD_SIZE]; strcpy(tmp,word); strcat(tmp,wordStarts[i+1]); breakAt = SplitWord(tmp); if (breakAt > 0) // replace words with the dual pair { wordStarts[i+1] = reuseAllocation(wordStarts[i+1],StoreWord(tmp+breakAt)->word); // set this to the second word (shared from within 1st word) return FindWord(tmp,breakAt,PRIMARY_CASE_ALLOWED)->word; // 1st word gets replaced, we added valid word after } } // remove any nondigit characters repeated more than once. Dont do this earlier, we want substitutions to have a chance at it first. ammmmmmazing static char word1[MAX_WORD_SIZE]; char* ptr = word-1; char* ptr1 = word1; while (*++ptr) { *ptr1 = *ptr; while (ptr[1] == *ptr1 && ptr[2] == *ptr1 && (*ptr1 < '0' || *ptr1 > '9')) ++ptr; // skip double repeats ++ptr1; } *ptr1 = 0; if (FindCanonical(word1,0,true) && !IsUpperCase(*word1)) return word1; // this is a different form of a canonical word so its ok // now use word spell checker char* d = SpellFix(word,i,PART_OF_SPEECH); return (d) ? d : NULL; }
void CTextWrap::WrapTextConsole(std::list<word>& words, float maxWidth, float maxHeight) { if (words.empty() || (GetLineHeight()<=0.0f)) return; const bool splitAllWords = false; const unsigned int maxLines = (unsigned int)std::floor(std::max(0.0f, maxHeight / GetLineHeight())); line* currLine; word linebreak; linebreak.isLineBreak = true; bool addEllipsis = false; bool currLineValid = false; // true if there was added any data to the current line std::list<word>::iterator wi = words.begin(); std::list<line> lines; lines.push_back(line()); currLine = &(lines.back()); currLine->start = words.begin(); for (; ;) { currLineValid = true; if (wi->isLineBreak) { currLine->forceLineBreak = true; currLine->end = wi; // start a new line after the '\n' lines.push_back(line()); currLineValid = false; currLine = &(lines.back()); currLine->start = wi; ++currLine->start; } else { currLine->width += wi->width; currLine->end = wi; if (currLine->width > maxWidth) { currLine->width -= wi->width; // line grew too long by adding the last word, insert a LineBreak const bool splitLastWord = (wi->width > (0.5 * maxWidth)); const float freeWordSpace = (maxWidth - currLine->width); if (splitAllWords || splitLastWord) { // last word W is larger than 0.5 * maxLineWidth, split it into // get 'L'eft and 'R'ight parts of the split (wL becomes Left, *wi becomes R) bool restart = (currLine->start == wi); // turns *wi into R word wL = SplitWord(*wi, freeWordSpace); if (splitLastWord && wL.width == 0.0f) { // With smart splitting it can happen that the word isn't split at all, // this can cause a race condition when the word is longer than maxWidth. // In this case we have to force an unaesthetic split. wL = SplitWord(*wi, freeWordSpace, false); } // increase by the width of the L-part of *wi currLine->width += wL.width; // insert the L-part right before R wi = words.insert(wi, wL); if (restart) currLine->start = wi; ++wi; } // insert the forced linebreak (either after W or before R) linebreak.pos = wi->pos; currLine->end = words.insert(wi, linebreak); while (wi != words.end() && wi->isSpace) wi = words.erase(wi); lines.push_back(line()); currLineValid = false; currLine = &(lines.back()); currLine->start = wi; --wi; // compensate the wi++ downwards } } ++wi; if (wi == words.end()) { break; } if (lines.size() > maxLines) { addEllipsis = true; break; } } // empty row if (!currLineValid || (currLine->start == words.end() && !currLine->forceLineBreak)) { lines.pop_back(); currLine = &(lines.back()); } // if we had to cut the text because of missing space, add an ellipsis if (addEllipsis) AddEllipsis(lines, words, maxWidth); wi = currLine->end; ++wi; wi = words.erase(wi, words.end()); }
void CTextWrap::AddEllipsis(std::list<line>& lines, std::list<word>& words, float maxWidth) { const float ellipsisAdvance = GetGlyph(ellipsisUTF16).advance; const float spaceAdvance = GetGlyph(spaceUTF16).advance; if (ellipsisAdvance > maxWidth) return; line* l = &(lines.back()); // If the last line ends with a linebreak, remove it std::list<word>::iterator wi_end = l->end; if (wi_end->isLineBreak) { if (l->start == l->end || l->end == words.begin()) { // there is just the linebreak in that line, so replace linebreak with just a null space word w; w.pos = wi_end->pos; w.isSpace = true; w.numSpaces = 0; l->start = words.insert(wi_end,w); l->end = l->start; words.erase(wi_end); } else { wi_end = words.erase(wi_end); l->end = --wi_end; } } // remove as many words until we have enough free space for the ellipsis while (l->end != l->start) { word& w = *l->end; // we have enough free space if (l->width + ellipsisAdvance < maxWidth) break; // we can cut the last word to get enough freespace (so show as many as possible characters of that word) if ( ((l->width - w.width + ellipsisAdvance) < maxWidth) && (w.width > ellipsisAdvance) ) { break; } l->width -= w.width; --(l->end); } // we don't even have enough space for the ellipsis word& w = *l->end; if ((l->width - w.width) + ellipsisAdvance > maxWidth) return; // sometimes words aren't hyphenated for visual aspects // but if we put an ellipsis in there, it is better to show as many as possible characters of those words std::list<word>::iterator nextwi(l->end); ++nextwi; if ( (!l->forceLineBreak) && (nextwi != words.end()) && (w.isSpace || w.isLineBreak) && (l->width + ellipsisAdvance < maxWidth) && !(nextwi->isSpace || nextwi->isLineBreak) ) { float spaceLeft = maxWidth - (l->width + ellipsisAdvance); l->end = words.insert( nextwi, SplitWord(*nextwi, spaceLeft, false) ); l->width += l->end->width; } // the last word in the line needs to be cut if (l->width + ellipsisAdvance > maxWidth) { word& w = *l->end; l->width -= w.width; float spaceLeft = maxWidth - (l->width + ellipsisAdvance); l->end = words.insert( l->end, SplitWord(w, spaceLeft, false) ); l->width += l->end->width; } // put in a space between words and the ellipsis (if there is enough space) if (l->forceLineBreak && !l->end->isSpace) { if (l->width + ellipsisAdvance + spaceAdvance <= maxWidth) { word space; space.isSpace = true; space.numSpaces = 1; space.width = spaceAdvance; std::list<word>::iterator wi(l->end); ++l->end; if (l->end == words.end()) { space.pos = wi->pos + wi->text.length() + 1; } else { space.pos = l->end->pos; } l->end = words.insert( l->end, space ); l->width += l->end->width; } } // add our ellipsis word ellipsis; ellipsis.text = toustring(ellipsisUTF8); ellipsis.width = ellipsisAdvance; std::list<word>::iterator wi(l->end); ++l->end; if (l->end == words.end()) { ellipsis.pos = wi->pos + wi->text.length() + 1; } else { ellipsis.pos = l->end->pos; } l->end = words.insert( l->end, ellipsis ); l->width += l->end->width; }