int Font::Index (const char* s, int len, int offset, boolean between) { register XFontStruct* i = (XFontStruct*)rep->info; register const char* p; register int n, w; int coff, cw; if (offset < 0 || *s == '\0' || len == 0) { return 0; } if (IsFixedWidth(i)) { cw = i->min_bounds.width; n = offset / cw; coff = offset % cw; } else { w = 0; for (p = s, n = 0; *p != '\0' && n < len; ++p, ++n) { cw = XTextWidth(i, p, 1); w += cw; if (w > offset) { break; } } coff = offset - w + cw; } if (between && coff > cw/2) { ++n; } return min(n, len); }
bool Text::FilterImplicitAttributes(XMLElement& dest) const { if (!UISelectable::FilterImplicitAttributes(dest)) return false; if (!IsFixedWidth()) { if (!RemoveChildXML(dest, "Size")) return false; if (!RemoveChildXML(dest, "Min Size")) return false; if (!RemoveChildXML(dest, "Max Size")) return false; } return true; }
void Text::UpdateText(bool onResize) { rowWidths_.clear(); printText_.clear(); if (font_) { FontFace* face = font_->GetFace(fontSize_); if (!face) return; rowHeight_ = face->GetRowHeight(); int width = 0; int height = 0; int rowWidth = 0; auto rowHeight = RoundToInt(rowSpacing_ * rowHeight_); // First see if the text must be split up if (!wordWrap_) { printText_ = unicodeText_; printToText_.resize(printText_.size()); for (unsigned i = 0; i < printText_.size(); ++i) printToText_[i] = i; } else { int maxWidth = GetWidth(); unsigned nextBreak = 0; unsigned lineStart = 0; printToText_.clear(); for (unsigned i = 0; i < unicodeText_.size(); ++i) { unsigned j; unsigned c = unicodeText_[i]; if (c != '\n') { bool ok = true; if (nextBreak <= i) { int futureRowWidth = rowWidth; for (j = i; j < unicodeText_.size(); ++j) { unsigned d = unicodeText_[j]; if (d == ' ' || d == '\n') { nextBreak = j; break; } const FontGlyph* glyph = face->GetGlyph(d); if (glyph) { futureRowWidth += glyph->advanceX_; if (j < unicodeText_.size() - 1) futureRowWidth += face->GetKerning(d, unicodeText_[j + 1]); } if (d == '-' && futureRowWidth <= maxWidth) { nextBreak = j + 1; break; } if (futureRowWidth > maxWidth) { ok = false; break; } } } if (!ok) { // If did not find any breaks on the line, copy until j, or at least 1 char, to prevent infinite loop if (nextBreak == lineStart) { while (i < j) { printText_.push_back(unicodeText_[i]); printToText_.push_back(i); ++i; } } // Eliminate spaces that have been copied before the forced break while (printText_.size() && printText_.back() == ' ') { printText_.pop_back(); printToText_.pop_back(); } printText_.push_back('\n'); printToText_.push_back(Min(i, unicodeText_.size() - 1)); rowWidth = 0; nextBreak = lineStart = i; } if (i < unicodeText_.size()) { // When copying a space, position is allowed to be over row width c = unicodeText_[i]; const FontGlyph* glyph = face->GetGlyph(c); if (glyph) { rowWidth += glyph->advanceX_; if (i < unicodeText_.size() - 1) rowWidth += face->GetKerning(c, unicodeText_[i + 1]); } if (rowWidth <= maxWidth) { printText_.push_back(c); printToText_.push_back(i); } } } else { printText_.push_back('\n'); printToText_.push_back(Min(i, unicodeText_.size() - 1)); rowWidth = 0; nextBreak = lineStart = i; } } } rowWidth = 0; for (unsigned i = 0; i < printText_.size(); ++i) { unsigned c = printText_[i]; if (c != '\n') { const FontGlyph* glyph = face->GetGlyph(c); if (glyph) { rowWidth += glyph->advanceX_; if (i < printText_.size() - 1) rowWidth += face->GetKerning(c, printText_[i + 1]); } } else { width = Max(width, rowWidth); height += rowHeight; rowWidths_.push_back(rowWidth); rowWidth = 0; } } if (rowWidth) { width = Max(width, rowWidth); height += rowHeight; rowWidths_.push_back(rowWidth); } // Set at least one row height even if text is empty if (!height) height = rowHeight; // Set minimum and current size according to the text size, but respect fixed width if set if (!IsFixedWidth()) { if (wordWrap_) SetMinWidth(0); else { SetMinWidth(width); SetWidth(width); } } SetFixedHeight(height); charLocationsDirty_ = true; } else { // No font, nothing to render pageGlyphLocations_.clear(); } // If wordwrap is on, parent may need layout update to correct for overshoot in size. However, do not do this when the // update is a response to resize, as that could cause infinite recursion if (wordWrap_ && !onResize) { UIElement* parent = GetParent(); if (parent && parent->GetLayoutMode() != LM_FREE) parent->UpdateLayout(); } }
void FlexGrid::Layout() { std::vector<double> heights(rows.size(), 0.0); std::vector<double> widths(defaultCols.size(), 0.0); Vec2 totalSize(0, 0); Vec2 padding2x = padding; padding2x *= 2; // First, measure each of the cells to determine the height of each row // and width of each column. auto heightIter = heights.begin(); auto widthIter = widths.begin(); for (auto &cols : rows) { for (auto &cell : cols) { if (cell) { Vec3 size = cell->Measure(); size += padding2x; if (size.x > *widthIter) { *widthIter = size.x; } if (size.y > *heightIter) { *heightIter = size.y; } } ++widthIter; } ++heightIter; widthIter = widths.begin(); } // If a fixed size is set, then scale the dimensions. if (IsFixedWidth()) { ScaleDimension(widths, fixedSize.x, padding.x, margin.x); } if (IsFixedHeight()) { ScaleDimension(heights, fixedSize.y, padding.y, margin.y); } // Move each cell contents into position. heightIter = heights.begin(); widthIter = widths.begin(); double x = 0; double y = 0; for (auto &cols : rows) { for (auto &cell : cols) { if (cell) { cell->SetExtents(x, y, *widthIter, *heightIter, padding.x, padding.y); } x += *widthIter + padding2x.x; if (x > totalSize.x) { totalSize.x = x; } x += margin.x; ++widthIter; } y += *heightIter + padding2x.y; totalSize.y = y; y += margin.y; ++heightIter; x = 0; widthIter = widths.begin(); } // Update the calculated size of the grid. size = totalSize; SUPER::SetSize(totalSize); }
void Text::UpdateText() { int width = 0; int height = 0; rowWidths_.Clear(); printText_.Clear(); PODVector<unsigned> printToText; if (font_) { const FontFace* face = font_->GetFace(fontSize_); if (!face) return; rowHeight_ = face->rowHeight_; int rowWidth = 0; int rowHeight = (int)(rowSpacing_ * rowHeight_); // First see if the text must be split up if (!wordWrap_) { printText_ = unicodeText_; printToText.Resize(printText_.Size()); for (unsigned i = 0; i < printText_.Size(); ++i) printToText[i] = i; } else { int maxWidth = GetWidth(); unsigned nextBreak = 0; unsigned lineStart = 0; for (unsigned i = 0; i < unicodeText_.Size(); ++i) { unsigned j; unsigned c = unicodeText_[i]; if (c != '\n') { bool ok = true; if (nextBreak <= i) { int futureRowWidth = rowWidth; for (j = i; j < unicodeText_.Size(); ++j) { unsigned d = unicodeText_[j]; if (d == ' ' || d == '\n') { nextBreak = j; break; } const FontGlyph* glyph = face->GetGlyph(d); if (glyph) { futureRowWidth += glyph->advanceX_; if (j < unicodeText_.Size() - 1) futureRowWidth += face->GetKerning(d, unicodeText_[j + 1]); } if (d == '-' && futureRowWidth <= maxWidth) { nextBreak = j + 1; break; } if (futureRowWidth > maxWidth) { ok = false; break; } } } if (!ok) { // If did not find any breaks on the line, copy until j, or at least 1 char, to prevent infinite loop if (nextBreak == lineStart) { while (i < j) { printText_.Push(unicodeText_[i]); printToText.Push(i); ++i; } } printText_.Push('\n'); printToText.Push(Min((int)i, (int)unicodeText_.Size() - 1)); rowWidth = 0; nextBreak = lineStart = i; } if (i < unicodeText_.Size()) { // When copying a space, position is allowed to be over row width c = unicodeText_[i]; const FontGlyph* glyph = face->GetGlyph(c); if (glyph) { rowWidth += glyph->advanceX_; if (i < text_.Length() - 1) rowWidth += face->GetKerning(c, unicodeText_[i + 1]); } if (rowWidth <= maxWidth) { printText_.Push(c); printToText.Push(i); } } } else { printText_.Push('\n'); printToText.Push(Min((int)i, (int)unicodeText_.Size() - 1)); rowWidth = 0; nextBreak = lineStart = i; } } } rowWidth = 0; for (unsigned i = 0; i < printText_.Size(); ++i) { unsigned c = printText_[i]; if (c != '\n') { const FontGlyph* glyph = face->GetGlyph(c); if (glyph) { rowWidth += glyph->advanceX_; if (i < printText_.Size() - 1) rowWidth += face->GetKerning(c, printText_[i + 1]); } } else { width = Max(width, rowWidth); height += rowHeight; rowWidths_.Push(rowWidth); rowWidth = 0; } } if (rowWidth) { width = Max(width, rowWidth); height += rowHeight; rowWidths_.Push(rowWidth); } // Set row height even if text is empty if (!height) height = rowHeight; // Store position & size of each character charPositions_.Resize(unicodeText_.Size() + 1); charSizes_.Resize(unicodeText_.Size()); unsigned rowIndex = 0; int x = GetRowStartPosition(rowIndex); int y = 0; for (unsigned i = 0; i < printText_.Size(); ++i) { charPositions_[printToText[i]] = IntVector2(x, y); unsigned c = printText_[i]; if (c != '\n') { const FontGlyph* glyph = face->GetGlyph(c); charSizes_[printToText[i]] = IntVector2(glyph ? glyph->advanceX_ : 0, rowHeight_); if (glyph) { x += glyph->advanceX_; if (i < printText_.Size() - 1) x += face->GetKerning(c, printText_[i + 1]); } } else { charSizes_[printToText[i]] = IntVector2::ZERO; x = GetRowStartPosition(++rowIndex); y += rowHeight; } } // Store the ending position charPositions_[unicodeText_.Size()] = IntVector2(x, y); } // Set minimum and current size according to the text size, but respect fixed width if set if (!IsFixedWidth()) { SetMinWidth(wordWrap_ ? 0 : width); SetWidth(width); } SetFixedHeight(height); }
boolean Font::FixedWidth () { register XFontStruct* i = (XFontStruct*)rep->info; return IsFixedWidth(i); }