22 #include "../lout/msg.h" 23 #include "../lout/misc.hh" 24 #include "../lout/unicode.hh" 25 #include "../lout/debug.hh" 43 int Textblock::CLASS_ID = -1;
45 Textblock::WordImgRenderer::WordImgRenderer (
Textblock *textblock,
50 this->textblock = textblock;
51 this->wordNo = wordNo;
55 Textblock::WordImgRenderer::~WordImgRenderer ()
60 void Textblock::WordImgRenderer::setData (
int xWordWidget,
int lineNo)
63 this->xWordWidget = xWordWidget;
64 this->lineNo = lineNo;
67 bool Textblock::WordImgRenderer::readyToDraw ()
73 && wordNo < textblock->words->size()
74 && lineNo < textblock->lines->size();
77 void Textblock::WordImgRenderer::getBgArea (
int *x,
int *y,
int *width,
81 Line *line = textblock->lines->getRef (lineNo);
82 *x = textblock->allocation.x + this->xWordWidget;
83 *y = textblock->lineYOffsetCanvas (line);
84 *width = textblock->words->getRef(wordNo)->size.width;
88 void Textblock::WordImgRenderer::getRefArea (
int *xRef,
int *yRef,
89 int *widthRef,
int *heightRef)
92 textblock->getPaddingArea (xRef, yRef, widthRef, heightRef);
97 return textblock->words->getRef(wordNo)->style;
100 void Textblock::WordImgRenderer::draw (
int x,
int y,
int width,
int height)
102 textblock->queueDrawArea (x - textblock->allocation.x,
103 y - textblock->allocation.y, width, height);
107 void Textblock::WordImgRenderer::print ()
109 printf (
"%p: word #%d, ",
this, wordNo);
110 if (wordNo < textblock->words->size())
111 textblock->printWordShort (textblock->words->getRef(wordNo));
113 printf (
"<word %d does not exist>", wordNo);
114 printf (
", data set: %s", dataSet ?
"yes" :
"no");
117 void Textblock::SpaceImgRenderer::getBgArea (
int *x,
int *y,
int *width,
120 WordImgRenderer::getBgArea (x, y, width, height);
122 *width = textblock->words->getRef(wordNo)->effSpace;
127 return textblock->words->getRef(wordNo)->spaceStyle;
130 void Textblock::SpaceImgRenderer::print ()
132 printf (
"%p: word FOR SPACE #%d, ",
this, wordNo);
133 if (wordNo < textblock->words->size())
134 textblock->printWordShort (textblock->words->getRef(wordNo));
136 printf (
"<word %d does not exist>", wordNo);
137 printf (
", data set: %s", dataSet ?
"yes" :
"no");
144 {
"\xc2\xad",
true,
false,
true, PENALTY_HYPHEN, -1 },
146 {
"-",
false,
true,
true, -1, PENALTY_HYPHEN },
148 {
"\xe2\x80\x90",
false,
true,
true, -1, PENALTY_HYPHEN },
150 {
"\xe2\x80\x94",
false,
true,
false,
151 PENALTY_EM_DASH_LEFT, PENALTY_EM_DASH_RIGHT }
170 int Textblock::penalties[PENALTY_NUM][2] = {
180 int Textblock::stretchabilityFactor = 100;
190 const char *Textblock::hyphenDrawChar =
"-";
192 void Textblock::setPenaltyHyphen (
int penaltyHyphen)
194 penalties[PENALTY_HYPHEN][0] = penaltyHyphen;
197 void Textblock::setPenaltyHyphen2 (
int penaltyHyphen2)
199 penalties[PENALTY_HYPHEN][1] = penaltyHyphen2;
202 void Textblock::setPenaltyEmDashLeft (
int penaltyLeftEmDash)
204 penalties[PENALTY_EM_DASH_LEFT][0] = penaltyLeftEmDash;
205 penalties[PENALTY_EM_DASH_LEFT][1] = penaltyLeftEmDash;
208 void Textblock::setPenaltyEmDashRight (
int penaltyRightEmDash)
210 penalties[PENALTY_EM_DASH_RIGHT][0] = penaltyRightEmDash;
213 void Textblock::setPenaltyEmDashRight2 (
int penaltyRightEmDash2)
215 penalties[PENALTY_EM_DASH_RIGHT][1] = penaltyRightEmDash2;
218 void Textblock::setStretchabilityFactor (
int stretchabilityFactor)
220 Textblock::stretchabilityFactor = stretchabilityFactor;
223 Textblock::Textblock (
bool limitTextWidth)
226 registerName (
"dw::Textblock", &CLASS_ID);
227 setFlags (BLOCK_LEVEL);
228 setFlags (USES_HINTS);
229 setButtonSensitive(
true);
231 hasListitemValue =
false;
234 ignoreLine1OffsetSometimes =
false;
235 mustQueueResize =
false;
250 nonTemporaryLines = 0;
256 wrapRefLines = wrapRefParagraphs = -1;
270 this->limitTextWidth = limitTextWidth;
274 hlStart[layer].index = 1;
275 hlStart[layer].nChar = 0;
276 hlEnd[layer].index = 0;
277 hlEnd[layer].nChar = 0;
281 Textblock::~Textblock ()
283 _MSG(
"Textblock::~Textblock\n");
288 for (
int i = 0; i < words->size(); i++) {
289 Word *word = words->getRef (i);
294 removeWordImgRenderer (i);
295 removeSpaceImgRenderer (i);
301 for (
int i = 0; i < anchors->size(); i++) {
302 Anchor *anchor = anchors->getRef (i);
304 removeAnchor(anchor->
name);
326 PRINTF (
"[%p] SIZE_REQUEST: ...\n",
this);
331 if (lines->size () > 0) {
332 Line *lastLine = lines->getRef (lines->size () - 1);
335 PRINTF (
"[%p] SIZE_REQUEST: lastLine->maxLineWidth = %d\n",
338 PRINTF (
"[%p] SIZE_REQUEST: lines[0]->boxAscent = %d\n",
339 this, lines->getRef(0)->boxAscent);
340 PRINTF (
"[%p] SIZE_REQUEST: lines[%d]->top = %d\n",
341 this, lines->size () - 1, lastLine->
top);
342 PRINTF (
"[%p] SIZE_REQUEST: lines[%d]->boxAscent = %d\n",
343 this, lines->size () - 1, lastLine->
boxAscent);
344 PRINTF (
"[%p] SIZE_REQUEST: lines[%d]->boxDescent = %d\n",
345 this, lines->size () - 1, lastLine->
boxDescent);
349 requisition->
ascent = lines->getRef(0)->boxAscent;
352 lines->getRef(0)->boxAscent;
354 requisition->
width = 0;
359 PRINTF (
"[%p] SIZE_REQUEST: inner padding = %d, boxDiffWidth = %d\n",
360 this, innerPadding, getStyle()->boxDiffWidth ());
362 requisition->
width += innerPadding + getStyle()->boxDiffWidth ();
363 requisition->
ascent += getStyle()->boxOffsetY ();
364 requisition->
descent += getStyle()->boxRestHeight ();
366 if (requisition->
width < availWidth)
367 requisition->
width = availWidth;
369 PRINTF (
"[%p] SIZE_REQUEST: %d x %d + %d\n",
this, requisition->
width,
408 PRINTF (
"[%p] GET_EXTREMES ...\n",
this);
412 if (paragraphs->size () == 0) {
417 Paragraph *lastPar = paragraphs->getLastRef ();
422 int diff = innerPadding + getStyle()->boxDiffWidth ();
426 PRINTF (
"[%p] GET_EXTREMES => %d / %d\n",
433 PRINTF (
"[%p] SIZE_ALLOCATE: %d, %d, %d x %d + %d\n",
434 this, allocation->
x, allocation->
y, allocation->
width,
439 int lineIndex, wordIndex;
446 if (allocation->
width != this->allocation.width) {
450 for (lineIndex = 0; lineIndex < lines->size (); lineIndex++) {
451 line = lines->getRef (lineIndex);
452 xCursor = lineXOffsetWidget (line);
454 for (wordIndex = line->
firstWord; wordIndex <= line->lastWord;
456 word = words->getRef (wordIndex);
458 if (wordIndex == lastWordDrawn + 1) {
459 redrawY =
misc::min (redrawY, lineYOffsetWidget (line));
464 childAllocation.
x = xCursor + allocation->
x;
473 lineYOffsetCanvasAllocation (line, allocation)
484 if (childAllocation.
x != oldChildAllocation->
x ||
485 childAllocation.
y != oldChildAllocation->
y ||
486 childAllocation.
width != oldChildAllocation->
width) {
490 redrawY =
misc::min (redrawY, lineYOffsetWidget (line));
493 oldChildAllocation->
y - this->allocation.y);
496 }
else if (childAllocation.
ascent + childAllocation.
descent !=
512 words->getRef (line->
lastWord)->content.type ==
513 core::Content::BREAK)) {
518 oldChildAllocation->
y - this->allocation.y +
519 oldChildAllocation->
ascent +
522 redrawY =
misc::min (redrawY, childChangedY);
524 redrawY =
misc::min (redrawY, lineYOffsetWidget (line));
534 for (
int i = 0; i < anchors->size(); i++) {
535 Anchor *anchor = anchors->getRef(i);
538 if (anchor->
wordIndex >= words->size()) {
541 Line *line = lines->getRef(findLineOfWord (anchor->
wordIndex));
542 y = lineYOffsetCanvasAllocation (line, allocation);
544 changeAnchor (anchor->
name, y);
548 void Textblock::resizeDrawImpl ()
550 queueDrawArea (0, redrawY, allocation.width, getHeight () - redrawY);
551 if (lines->size () > 0) {
552 Line *lastLine = lines->getRef (lines->size () - 1);
559 redrawY = getHeight ();
562 void Textblock::markSizeChange (
int ref)
564 PRINTF (
"[%p] MARK_SIZE_CHANGE (%d): %d => ...\n",
this, ref, wrapRefLines);
572 if (wrapRefLines == -1)
575 wrapRefLines =
misc::min (wrapRefLines, ref);
578 PRINTF (
" ... => %d\n", wrapRefLine);
584 markExtremesChange (ref);
587 void Textblock::markExtremesChange (
int ref)
589 PRINTF (
"[%p] MARK_EXTREMES_CHANGE (%d): %d => ...\n",
590 this, ref, wrapRefParagraphs);
598 if (wrapRefParagraphs == -1)
599 wrapRefParagraphs = ref;
601 wrapRefParagraphs =
misc::min (wrapRefParagraphs, ref);
604 PRINTF (
" ... => %d\n", wrapRefParagraphs);
607 void Textblock::setWidth (
int width)
611 if (availWidth != width || limitTextWidth) {
618 queueResize (0,
false);
619 mustQueueResize =
false;
624 void Textblock::setAscent (
int ascent)
626 if (availAscent != ascent) {
632 availAscent = ascent;
633 queueResize (0,
false);
634 mustQueueResize =
false;
638 void Textblock::setDescent (
int descent)
640 if (availDescent != descent) {
646 availDescent = descent;
647 queueResize (0,
false);
648 mustQueueResize =
false;
654 return sendSelectionEvent (core::SelectionState::BUTTON_PRESS, event);
659 return sendSelectionEvent (core::SelectionState::BUTTON_RELEASE, event);
670 return sendSelectionEvent (core::SelectionState::BUTTON_MOTION, event);
673 int linkOld = hoverLink;
679 setCursor (getStyle()->cursor);
684 setCursor (style->
cursor);
685 hoverLink = style->
x_link;
698 _MSG(
"MN tb=%p tooltipOld=%p hoverTooltip=%p\n",
700 if (hoverLink != linkOld) {
702 return layout->emitLinkEnter (
this, hoverLink, -1, -1, -1);
704 return hoverLink != -1;
722 layout->emitLinkEnter (
this, -1, -1, -1, -1);
738 int charPos = 0, link = -1;
741 if (words->size () == 0) {
744 Line *lastLine = lines->getRef (lines->size () - 1);
745 int yFirst = lineYOffsetCanvasI (0);
746 int yLast = lineYOffsetCanvas (lastLine) + lastLine->
boxAscent +
751 }
else if (event->
yCanvas >= yLast) {
753 wordIndex = words->size () - 1;
754 charPos = core::SelectionState::END_OF_WORD;
756 Line *line = lines->getRef (findLineIndex (event->
yWidget));
763 charPos = core::SelectionState::END_OF_WORD;
764 }
else if (event->
xWidget < lineXOffsetWidget (line)) {
768 int nextWordStartX = lineXOffsetWidget (line);
771 wordIndex <= line->lastWord;
773 Word *word = words->getRef (wordIndex);
774 int wordStartX = nextWordStartX;
778 if (event->
xWidget >= wordStartX &&
779 event->
xWidget < nextWordStartX) {
781 int yWidgetBase = lineYOffsetWidget (line) + line->
boxAscent;
784 charPos = core::SelectionState::END_OF_WORD;
785 if (wordIndex < line->lastWord &&
786 (words->getRef(wordIndex + 1)->content.type !=
787 core::Content::BREAK) &&
800 int glyphX = wordStartX;
801 int isStartWord = word->
flags & Word::WORD_START;
802 int isEndWord = word->
flags & Word::WORD_END;
815 nextCharPos - charPos, word->
style,
816 isStartWord && charPos == 0,
819 if (event->
xWidget > glyphX + glyphWidth) {
820 glyphX += glyphWidth;
821 charPos = nextCharPos;
823 }
else if (event->
xWidget >= glyphX + glyphWidth/2){
826 charPos = nextCharPos;
832 nextCharPos - charPos,
834 isStartWord && charPos == 0,
839 charPos = nextCharPos;
847 if (event->
xWidget >= (wordStartX + nextWordStartX) /2)
848 charPos = core::SelectionState::END_OF_WORD;
858 charPos = core::SelectionState::END_OF_WORD;
865 r = selectionHandleEvent (eventType, it, charPos, link, event);
870 void Textblock::removeChild (Widget *child)
888 int availWidth, availAscent, availDescent;
892 availWidth = this->availWidth - getStyle()->
boxDiffWidth () - innerPadding;
893 availAscent = this->availAscent - getStyle()->boxDiffHeight ();
894 availDescent = this->availDescent;
944 int x,
int yBase,
int width)
974 const char *text,
int start,
int len,
bool isStart,
985 str = layout->textToUpper(text + start, len);
988 str = layout->textToLower(text + start, len);
996 bool initial_seen =
false;
998 for (
int i = 0; i < start; i++)
999 if (!ispunct(text[i]))
1000 initial_seen =
true;
1006 while (ispunct(text[after]))
1009 after = layout->nextGlyph(text, after);
1013 char *initial = layout->textToUpper(text, after);
1014 int newlen = strlen(initial) + len-after;
1015 str = (
char *)malloc(newlen + 1);
1016 strcpy(str, initial);
1017 strncpy(str + strlen(str), text+after, len-after);
1025 str ? str : text + start, str ? strlen(str) : len);
1039 void Textblock::drawWord (
Line *line,
int wordIndex1,
int wordIndex2,
1041 int xWidget,
int yWidgetBase)
1044 bool drawHyphen = wordIndex2 == line->
lastWord 1045 && (words->getRef(wordIndex2)->flags & Word::DIV_CHAR_AT_EOL);
1049 for (
int i = wordIndex1; i <= wordIndex2; i++)
1050 w += words->getRef(i)->size.width;
1051 w += words->getRef(wordIndex2)->hyphenWidth;
1052 drawBox (view, style, area, xWidget, yWidgetBase - line->
boxAscent,
1056 if (wordIndex1 == wordIndex2 && !drawHyphen) {
1058 Word *word = words->getRef (wordIndex1);
1060 false, style, view, area, xWidget, yWidgetBase);
1063 int l = 0, totalWidth = 0;
1064 for (
int i = wordIndex1; i <= wordIndex2; i++) {
1065 Word *w = words->getRef (i);
1070 char text[l + (drawHyphen ? strlen (hyphenDrawChar) : 0) + 1];
1072 for (
int i = wordIndex1; i <= wordIndex2; i++) {
1073 const char * t = words->getRef(i)->content.text;
1074 strcpy (text + p, t);
1079 for (
int i = 0; hyphenDrawChar[i]; i++)
1080 text[p++] = hyphenDrawChar[i];
1084 drawWord0 (wordIndex1, wordIndex2, text, totalWidth, drawHyphen,
1085 style, view, area, xWidget, yWidgetBase);
1092 void Textblock::drawWord0 (
int wordIndex1,
int wordIndex2,
1093 const char *text,
int totalWidth,
bool drawHyphen,
1097 int xWorld = allocation.x + xWidget;
1106 yWorldBase = yWidgetBase + allocation.y;
1108 bool isStartTotal = words->getRef(wordIndex1)->flags & Word::WORD_START;
1109 bool isEndTotal = words->getRef(wordIndex2)->flags & Word::WORD_START;
1110 drawText (view, style, core::style::Color::SHADING_NORMAL, xWorld,
1111 yWorldBase, text, 0, strlen (text), isStartTotal, isEndTotal);
1114 decorateText(view, style, core::style::Color::SHADING_NORMAL, xWorld,
1115 yWorldBase, totalWidth);
1118 if (wordIndex1 <= hlEnd[layer].index &&
1119 wordIndex2 >= hlStart[layer].index) {
1120 const int wordLen = strlen (text);
1125 if (hlStart[layer].index < wordIndex1)
1130 (
int)strlen (words->getRef(hlStart[layer].index)
1132 for (
int i = wordIndex1; i < hlStart[layer].index; i++)
1135 firstCharIdx += strlen (words->getRef(i)->content.text);
1138 if (hlEnd[layer].index > wordIndex2)
1139 lastCharIdx = wordLen;
1143 (
int)strlen (words->getRef(hlEnd[layer].index)
1145 for (
int i = wordIndex1; i < hlEnd[layer].index; i++)
1148 lastCharIdx += strlen (words->getRef(i)->content.text);
1153 xStart += textWidth (text, 0, firstCharIdx, style,
1155 isEndTotal && text[firstCharIdx] == 0);
1158 if (!drawHyphen && firstCharIdx == 0 && lastCharIdx == wordLen)
1161 width = textWidth (text, firstCharIdx,
1162 lastCharIdx - firstCharIdx, style,
1163 isStartTotal && firstCharIdx == 0,
1164 isEndTotal && text[lastCharIdx] == 0);
1170 wordBgColor = getBgColor();
1174 wordBgColor, core::style::Color::SHADING_INVERSE,
true, xStart,
1179 drawText (view, style, core::style::Color::SHADING_INVERSE, xStart,
1180 yWorldBase, text, firstCharIdx,
1181 lastCharIdx - firstCharIdx,
1182 isStartTotal && firstCharIdx == 0,
1183 isEndTotal && lastCharIdx == wordLen);
1186 decorateText(view, style, core::style::Color::SHADING_INVERSE,
1187 xStart, yWorldBase, width);
1199 Word *word = words->getRef(wordIndex);
1200 int xWorld = allocation.x + xWidget;
1203 bool highlight =
false;
1211 yWorldBase = allocation.y + yWidgetBase;
1214 if (hlStart[layer].index <= wordIndex &&
1215 hlEnd[layer].index > wordIndex) {
1224 spaceBgColor = getBgColor();
1227 spaceBgColor, core::style::Color::SHADING_INVERSE,
true, xWorld,
1233 core::style::Color::SHADING_INVERSE :
1234 core::style::Color::SHADING_NORMAL;
1236 decorateText(view, style, shading, xWorld, yWorldBase, word->
effSpace);
1248 int xWidget = lineXOffsetWidget(line);
1249 int yWidgetBase = lineYOffsetWidget (line) + line->
boxAscent;
1252 wordIndex <= line->lastWord && xWidget < area->x + area->
width;
1254 Word *word = words->getRef(wordIndex);
1262 if (word->
content.
type == core::Content::WIDGET) {
1267 child->
draw (view, &childArea);
1269 int wordIndex2 = wordIndex;
1270 while (wordIndex2 < line->lastWord &&
1271 (words->getRef(wordIndex2)->flags
1272 & Word::DRAW_AS_ONE_TEXT) &&
1273 word->
style == words->getRef(wordIndex2 + 1)->style)
1276 drawWord(line, wordIndex, wordIndex2, view, area,
1277 xWidget, yWidgetBase);
1279 for (
int i = wordIndex; i <= wordIndex2; i++)
1280 wordSize += words->getRef(i)->size.width;
1282 wordIndex = wordIndex2;
1283 word = words->getRef(wordIndex);
1287 if (word->
effSpace > 0 && wordIndex < line->lastWord &&
1288 words->getRef(wordIndex + 1)->content.type !=
1289 core::Content::BREAK) {
1295 drawSpace(wordIndex, view, area, xWidget + wordSize,
1301 xWidget += wordSize + word->
effSpace;
1308 int Textblock::findLineIndex (
int y)
1310 int maxIndex = lines->size () - 1;
1311 int step, index, low = 0;
1313 step = (lines->size() + 1) >> 1;
1314 while ( step > 1 ) {
1316 if (index <= maxIndex &&
1317 lineYOffsetWidgetI (index) <= y)
1319 step = (step + 1) >> 1;
1322 if (low < maxIndex && lineYOffsetWidgetI (low + 1) <= y)
1341 int Textblock::findLineOfWord (
int wordIndex)
1343 int high = lines->size () - 1, index, low = 0;
1346 if (wordIndex < 0 || wordIndex >= words->size ())
1350 index = (low + high) / 2;
1351 if (wordIndex >= lines->getRef(index)->firstWord) {
1352 if (wordIndex <= lines->getRef(index)->lastWord)
1364 int Textblock::findParagraphOfWord (
int wordIndex)
1366 int high = paragraphs->size () - 1, index, low = 0;
1368 if (wordIndex < 0 || wordIndex >= words->size () ||
1371 (paragraphs->size () > 0 &&
1372 wordIndex > paragraphs->getLastRef()->lastWord))
1376 index = (low + high) / 2;
1377 if (wordIndex >= paragraphs->getRef(index)->firstWord) {
1378 if (wordIndex <= paragraphs->getRef(index)->lastWord)
1392 int lineIndex, wordIndex;
1393 int xCursor, lastXCursor, yWidgetBase;
1399 if ((lineIndex = findLineIndex (y)) >= lines->size ())
1401 line = lines->getRef (lineIndex);
1402 yWidgetBase = lineYOffsetWidget (line) + line->
boxAscent;
1406 xCursor = lineXOffsetWidget (line);
1407 for (wordIndex = line->
firstWord; wordIndex <= line->lastWord;wordIndex++) {
1408 word = words->getRef (wordIndex);
1409 lastXCursor = xCursor;
1411 if (lastXCursor <= x && xCursor > x) {
1412 if (x >= xCursor - word->
effSpace) {
1413 if (wordIndex < line->lastWord &&
1414 (words->getRef(wordIndex + 1)->content.type !=
1415 core::Content::BREAK) &&
1417 y <= yWidgetBase + word->spaceStyle->font->descent) {
1423 y <= yWidgetBase + word->size.descent)
1435 PRINTF (
"DRAW: %d, %d, %d x %d\n",
1441 drawWidgetBox (view, area,
false);
1443 lineIndex = findLineIndex (area->
y);
1445 for (; lineIndex < lines->size (); lineIndex++) {
1446 line = lines->getRef (lineIndex);
1447 if (lineYOffsetWidget (line) >= area->
y + area->
height)
1450 drawLine (line, view, area);
1461 int wordNo = words->
size () - 1;
1463 fillWord (wordNo, width, ascent, descent, flags, style);
1464 return words->getRef (wordNo);;
1470 void Textblock::initWord (
int wordNo)
1472 Word *word = words->getRef (wordNo);
1479 void Textblock::removeWordImgRenderer (
int wordNo)
1481 Word *word = words->getRef (wordNo);
1491 void Textblock::setWordImgRenderer (
int wordNo)
1493 Word *word = words->getRef (wordNo);
1503 void Textblock::removeSpaceImgRenderer (
int wordNo)
1505 Word *word = words->getRef (wordNo);
1515 void Textblock::setSpaceImgRenderer (
int wordNo)
1517 Word *word = words->getRef (wordNo);
1527 void Textblock::fillWord (
int wordNo,
int width,
int ascent,
int descent,
1530 Word *word = words->getRef (wordNo);
1539 word->
flags = flags;
1541 removeWordImgRenderer (wordNo);
1542 removeSpaceImgRenderer (wordNo);
1544 word->
style = style;
1547 setWordImgRenderer (wordNo);
1548 setSpaceImgRenderer (wordNo);
1559 int Textblock::textWidth(
const char *text,
int start,
int len,
1570 ret = layout->textWidth(style->
font, text+start, len);
1573 str = layout->textToUpper(text+start, len);
1574 ret = layout->textWidth(style->
font, str, strlen(str));
1577 str = layout->textToLower(text+start, len);
1578 ret = layout->textWidth(style->
font, str, strlen(str));
1583 bool initial_seen =
false;
1585 for (
int i = 0; i < start; i++)
1586 if (!ispunct(text[i]))
1587 initial_seen =
true;
1589 ret = layout->textWidth(style->
font, text+start, len);
1594 while (ispunct(text[after]))
1597 after = layout->nextGlyph(text, after);
1600 str = layout->textToUpper(text, after);
1601 ret = layout->textWidth(style->
font, str, strlen(str)) +
1602 layout->textWidth(style->
font, text+after, len-after);
1605 ret = layout->textWidth(style->
font, text+start, len);
1621 void Textblock::calcTextSize (
const char *text,
size_t len,
1625 size->
width = textWidth (text, 0, len, style, isStart, isEnd);
1635 int height, leading;
1654 leading = height - style->
font->
size;
1656 size->
ascent += leading / 2;
1657 size->
descent += leading - (leading / 2);
1676 void Textblock::addText (
const char *text,
size_t len,
1679 PRINTF (
"[%p] ADD_TEXT (%d characters)\n",
this, (
int)len);
1684 for (
const char *s = text; s; s =
nextUtf8Char (s, text + len - s)) {
1686 for (
int j = 0; foundDiv == -1 && j < NUM_DIV_CHARS; j++) {
1687 int lDiv = strlen (divChars[j].s);
1688 if (s <= text + len - lDiv) {
1689 if (memcmp (s, divChars[j].s, lDiv *
sizeof (
char)) == 0)
1694 if (foundDiv != -1) {
1695 if (divChars[foundDiv].penaltyIndexLeft != -1)
1697 if (divChars[foundDiv].penaltyIndexRight != -1)
1702 if (numParts == 1) {
1706 calcTextSize (text, len, style, &size,
true,
true);
1707 addText0 (text, len,
1708 Word::CAN_BE_HYPHENATED | Word::WORD_START | Word::WORD_END,
1715 PRINTF (
"HYPHENATION: '");
1716 for (
size_t i = 0; i < len; i++)
1718 PRINTF (
"', with %d parts\n", numParts);
1721 int n = 0, totalLenCharRemoved = 0;
1722 int partPenaltyIndex[numParts - 1];
1723 int partStart[numParts], partEnd[numParts];
1724 bool charRemoved[numParts - 1], canBeHyphenated[numParts + 1];
1725 bool permDivChar[numParts - 1], unbreakableForMinWidth[numParts - 1];
1726 canBeHyphenated[0] = canBeHyphenated[numParts] =
true;
1728 partEnd[numParts - 1] = len;
1730 for (
const char *s = text; s; s =
nextUtf8Char (s, text + len - s)) {
1732 for (
int j = 0; foundDiv == -1 && j < NUM_DIV_CHARS; j++) {
1733 int lDiv = strlen (divChars[j].s);
1734 if (s <= text + len - lDiv) {
1735 if (memcmp (s, divChars[j].s, lDiv *
sizeof (
char)) == 0)
1740 if (foundDiv != -1) {
1741 int lDiv = strlen (divChars[foundDiv].s);
1743 if (divChars[foundDiv].charRemoved) {
1744 assert (divChars[foundDiv].penaltyIndexLeft != -1);
1745 assert (divChars[foundDiv].penaltyIndexRight == -1);
1747 partPenaltyIndex[n] = divChars[foundDiv].penaltyIndexLeft;
1748 charRemoved[n] =
true;
1749 permDivChar[n] =
false;
1750 unbreakableForMinWidth[n] =
1751 divChars[foundDiv].unbreakableForMinWidth;
1752 canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated;
1753 partEnd[n] = s - text;
1754 partStart[n + 1] = s - text + lDiv;
1756 totalLenCharRemoved += lDiv;
1758 assert (divChars[foundDiv].penaltyIndexLeft != -1 ||
1759 divChars[foundDiv].penaltyIndexRight != -1);
1761 if (divChars[foundDiv].penaltyIndexLeft != -1) {
1762 partPenaltyIndex[n] = divChars[foundDiv].penaltyIndexLeft;
1763 charRemoved[n] =
false;
1764 permDivChar[n] =
false;
1765 unbreakableForMinWidth[n] =
1766 divChars[foundDiv].unbreakableForMinWidth;
1767 canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated;
1768 partEnd[n] = s - text;
1769 partStart[n + 1] = s - text;
1773 if (divChars[foundDiv].penaltyIndexRight != -1) {
1774 partPenaltyIndex[n] = divChars[foundDiv].penaltyIndexRight;
1775 charRemoved[n] =
false;
1776 permDivChar[n] =
true;
1777 unbreakableForMinWidth[n] =
1778 divChars[foundDiv].unbreakableForMinWidth;
1779 canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated;
1780 partEnd[n] = s - text + lDiv;
1781 partStart[n + 1] = s - text + lDiv;
1789 const char *textWithoutHyphens;
1790 char textWithoutHyphensBuf[len - totalLenCharRemoved];
1791 int *breakPosWithoutHyphens, breakPosWithoutHyphensBuf[numParts - 1];
1793 if (totalLenCharRemoved == 0) {
1795 textWithoutHyphens = text;
1799 breakPosWithoutHyphens = partEnd;
1802 textWithoutHyphens = textWithoutHyphensBuf;
1803 breakPosWithoutHyphens = breakPosWithoutHyphensBuf;
1806 for (
int i = 0; i < numParts; i++) {
1807 memmove (textWithoutHyphensBuf + n, text + partStart[i],
1808 partEnd[i] - partStart[i]);
1809 n += partEnd[i] - partStart[i];
1810 if (i < numParts - 1)
1811 breakPosWithoutHyphensBuf[i] = n;
1815 PRINTF(
"H... without hyphens: '");
1816 for (
size_t i = 0; i < len - totalLenCharRemoved; i++)
1817 PUTCHAR(textWithoutHyphens[i]);
1821 calcTextSizes (textWithoutHyphens, len - totalLenCharRemoved, style,
1822 numParts - 1, breakPosWithoutHyphens, wordSize);
1825 for (
int i = 0; i < numParts; i++) {
1831 if (canBeHyphenated[i] && canBeHyphenated[i + 1])
1832 flags |= Word::CAN_BE_HYPHENATED;
1834 if(i < numParts - 1) {
1836 flags |= Word::DIV_CHAR_AT_EOL;
1839 flags |= Word::PERM_DIV_CHAR;
1840 if (unbreakableForMinWidth[i])
1841 flags |= Word::UNBREAKABLE_FOR_MIN_WIDTH;
1843 flags |= Word::DRAW_AS_ONE_TEXT;
1847 flags |= Word::WORD_START;
1848 if (i == numParts - 1)
1849 flags |= Word::WORD_END;
1851 addText0 (text + partStart[i], partEnd[i] - partStart[i],
1852 flags, style, &wordSize[i]);
1863 if(i < numParts - 1) {
1864 Word *word = words->getLastRef();
1866 setBreakOption (word, style, penalties[partPenaltyIndex[i]][0],
1867 penalties[partPenaltyIndex[i]][1],
false);
1876 layout->textWidth (word->
style->
font, hyphenDrawChar,
1877 strlen (hyphenDrawChar));
1879 accumulateWordData (words->size() - 1);
1880 correctLastWordExtremes ();
1886 void Textblock::calcTextSizes (
const char *text,
size_t textLen,
1888 int numBreaks,
int *breakPos,
1892 int lastStart = breakPos[numBreaks - 1];
1893 calcTextSize (text + lastStart, textLen - lastStart, style,
1894 &wordSize[numBreaks],
true,
true);
1896 PRINTF(
"H... [%d] '", numBreaks);
1897 for (
size_t i = 0; i < textLen - lastStart; i++)
1899 PRINTF(
"' -> %d\n", wordSize[numBreaks].width);
1903 for (
int i = numBreaks - 1; i >= 0; i--) {
1904 int start = (i == 0) ? 0 : breakPos[i - 1];
1905 calcTextSize (text + start, textLen - start, style, &wordSize[i],
1906 i == 0, i == numBreaks - 1);
1908 PRINTF(
"H... [%d] '", i);
1909 for (
size_t j = 0; j < textLen - start; j++)
1911 PRINTF(
"' -> %d\n", wordSize[i].width);
1913 for (
int j = i + 1; j < numBreaks + 1; j++) {
1915 PRINTF(
"H... - %d = %d\n", wordSize[j].width, wordSize[i].width);
1923 void Textblock::addText0 (
const char *text,
size_t len,
short flags,
1937 word->
content.
text = layout->textZone->strndup(text, len);
1939 processWord (words->size () - 1);
1956 PRINTF (
"%p becomes child of %p\n", widget,
this);
1961 calcWidgetSize (widget, &size);
1970 processWord (words->size () - 1);
1994 if (wasAllocated ()) {
1995 if (lines->size () == 0)
1998 y = allocation.y + lineYOffsetWidgetI (lines->size () - 1);
1999 copy = Widget::addAnchor (name, y);
2001 copy = Widget::addAnchor (name);
2012 anchors->increase();
2013 anchor = anchors->getRef(anchors->size() - 1);
2014 anchor->
name = copy;
2026 int wordIndex = words->size () - 1;
2027 if (wordIndex >= 0) {
2028 fillSpace (wordIndex, style);
2029 accumulateWordData (wordIndex);
2030 correctLastWordExtremes ();
2042 int wordIndex = words->size () - 1;
2043 if (wordIndex >= 0) {
2044 setBreakOption (words->getRef(wordIndex), style, 0, 0, forceBreak);
2046 correctLastWordExtremes ();
2066 Word *word = words->getRef (wordNo);
2072 setBreakOption (word, style, 0, 0,
false);
2086 removeSpaceImgRenderer (wordNo);
2092 setSpaceImgRenderer (wordNo);
2102 int breakPenalty1,
int breakPenalty2,
2108 if (forceBreak || isBreakAllowed (word))
2115 bool Textblock::isBreakAllowed (
Word *word)
2144 if (words->size () == 0 ||
2145 (hasListitemValue && words->size () == 1)) {
2156 widget->getParent() &&
2157 widget->getParent()->instanceOf (Textblock::CLASS_ID);
2158 widget = widget->getParent ()) {
2161 bool isfirst = (textblock2->
words->getRef(index)->content.type
2162 == core::Content::WIDGET
2163 && textblock2->
words->getRef(index)->content.widget
2168 int lineno = widget->parentRef;
2173 ->getRef(lineno - 1)->firstWord)) &&
2190 if ((word = words->getRef(words->size () - 1)) &&
2192 Line *lastLine = lines->getRef (lines->size () - 1);
2203 word = addWord (0, 0, 0, 0, style);
2208 processWord (words->size () - 1);
2218 if (words->size () == 0 ||
2219 words->getRef(words->size () - 1)->content.type == core::Content::BREAK)
2226 word = addWord (0, 0, 0, 0, style);
2233 processWord (words->size () - 1);
2245 int lineIndex, wordIndex;
2248 if (x < allocation.x ||
2250 x > allocation.x + allocation.width ||
2251 y > allocation.y + getHeight ()) {
2255 lineIndex = findLineIndex (y - allocation.y);
2257 if (lineIndex < 0 || lineIndex >= lines->size ()) {
2261 line = lines->getRef (lineIndex);
2263 for (wordIndex = line->
firstWord; wordIndex <= line->lastWord;wordIndex++) {
2264 Word *word = words->getRef (wordIndex);
2266 if (word->
content.
type == core::Content::WIDGET) {
2271 return childAtPoint;
2286 if (lines->size() > 0) {
2288 Line *lastLine = lines->getRef (lines->size () - 1);
2290 if (lastLine->
breakSpace != 0 && (parent = getParent()) &&
2291 parent->instanceOf (Textblock::CLASS_ID)) {
2304 void Textblock::flush ()
2306 PRINTF (
"[%p] FLUSH => %s (parentRef = %d)\n",
2307 this, mustQueueResize ?
"true" :
"false", parentRef);
2309 if (mustQueueResize) {
2310 queueResize (-1,
true);
2311 mustQueueResize =
false;
2318 void Textblock::changeLinkColor (
int link,
int newColor)
2320 for (
int lineIndex = 0; lineIndex < lines->size(); lineIndex++) {
2321 bool changed =
false;
2322 Line *line = lines->getRef (lineIndex);
2325 for (wordIdx = line->
firstWord; wordIdx <= line->lastWord; wordIdx++){
2326 Word *word = words->getRef(wordIdx);
2332 case core::Content::TEXT:
2334 styleAttrs = *old_style;
2335 styleAttrs.
color = core::style::Color::create (layout,
2337 word->
style = core::style::Style::create (&styleAttrs);
2340 styleAttrs = *old_style;
2341 styleAttrs.
color = core::style::Color::create (layout,
2343 word->
spaceStyle = core::style::Style::create(&styleAttrs);
2347 case core::Content::WIDGET:
2350 styleAttrs.
color = core::style::Color::create (layout,
2353 core::style::Color::create (layout, newColor));
2354 widget->
setStyle(core::style::Style::create (&styleAttrs));
2364 queueDrawArea (0, lineYOffsetWidget(line), allocation.width,
2370 bool includeFirstSpace,
bool includeLastSpace)
2374 void Textblock::queueDrawRange (
int index1,
int index2)
2379 from =
misc::min (from, words->size () - 1);
2381 to =
misc::min (to, words->size () - 1);
2384 int line1idx = findLineOfWord (from);
2385 int line2idx = findLineOfWord (to);
2387 if (line1idx >= 0 && line2idx >= 0) {
2388 Line *line1 = lines->getRef (line1idx),
2389 *line2 = lines->getRef (line2idx);
2390 int y = lineYOffsetWidget (line1) + line1->
boxAscent -
2392 int h = lineYOffsetWidget (line2) + line2->boxAscent +
2393 line2->contentDescent - y;
2395 queueDrawArea (0, y, allocation.width, h);