Vector2I GUIInputCaret::getCaretPosition(const Vector2I& offset) const { if(mNumChars > 0 && isDescValid()) { UINT32 curPos = 0; UINT32 numLines = getNumLines(); for(UINT32 i = 0; i < numLines; i++) { const GUIInputLineDesc& lineDesc = getLineDesc(i); if(mCaretPos == curPos) { // Caret is on line start return Vector2I(offset.x, lineDesc.getLineYStart() + getTextOffset().y); } curPos += lineDesc.getEndChar(false) - lineDesc.getStartChar() + 1; // + 1 for special line start position } UINT32 charIdx = getCharIdxAtCaretPos(); if(charIdx > 0) charIdx -= 1; charIdx = std::min((UINT32)(mNumChars - 1), charIdx); Rect2I charRect = getCharRect(charIdx); UINT32 lineIdx = getLineForChar(charIdx); UINT32 yOffset = getLineDesc(lineIdx).getLineYStart() + getTextOffset().y; return Vector2I(charRect.x + charRect.width, yOffset); } return offset; }
INT32 GUIInputTool::getCharIdxAtPos(const Vector2I& pos) const { Vector2 vecPos((float)pos.x, (float)pos.y); UINT32 lineStartChar = 0; UINT32 lineEndChar = 0; UINT32 numNewlineChars = 0; UINT32 lineIdx = 0; for(auto& line : mLineDescs) { INT32 lineStart = line.getLineYStart() + getTextOffset().y; if(pos.y >= lineStart && pos.y < (lineStart + (INT32)line.getLineHeight())) { lineStartChar = line.getStartChar(); lineEndChar = line.getEndChar(false); break; } // Newline chars count in the startChar/endChar variables, but don't actually exist in the buffers // so we need to filter them out numNewlineChars += (line.hasNewlineChar() ? 1 : 0); lineIdx++; } UINT32 lineStartQuad = lineStartChar - numNewlineChars; UINT32 lineEndQuad = lineEndChar - numNewlineChars; float nearestDist = std::numeric_limits<float>::max(); UINT32 nearestChar = 0; bool foundChar = false; Vector2I textOffset = getTextOffset(); for(UINT32 i = lineStartQuad; i < lineEndQuad; i++) { UINT32 curVert = i * 4; float centerX = mQuads[curVert + 0].x + mQuads[curVert + 1].x; centerX *= 0.5f; centerX += textOffset.x; float dist = Math::abs(centerX - vecPos.x); if(dist < nearestDist) { nearestChar = i + numNewlineChars; nearestDist = dist; foundChar = true; } } if(!foundChar) return -1; return nearestChar; }
void GUIInputCaret::moveCaretToPos(const Vector2I& pos) { INT32 charIdx = getCharIdxAtPos(pos); if(charIdx != -1) { Rect2I charRect = getCharRect(charIdx); float xCenter = charRect.x + charRect.width * 0.5f; if(pos.x <= xCenter) moveCaretToChar(charIdx, CARET_BEFORE); else moveCaretToChar(charIdx, CARET_AFTER); } else { UINT32 numLines = getNumLines(); if(numLines == 0) { mCaretPos = 0; return; } UINT32 curPos = 0; for(UINT32 i = 0; i < numLines; i++) { const GUIInputLineDesc& line = getLineDesc(i); INT32 lineStart = line.getLineYStart() + getTextOffset().y; if(pos.y >= lineStart && pos.y < (lineStart + (INT32)line.getLineHeight())) { mCaretPos = curPos; return; } UINT32 numChars = line.getEndChar(false) - line.getStartChar() + 1; // +1 For extra line start position curPos += numChars; } { const GUIInputLineDesc& firstLine = getLineDesc(0); INT32 lineStart = firstLine.getLineYStart() + getTextOffset().y; if(pos.y < lineStart) // Before first line mCaretPos = 0; else // After last line mCaretPos = curPos - 1; } } }
void Graphics3DExtrude::drawCharacters( const TextLayoutResult& layoutResult, const UIFontUnrecPtr TheFont) const { glBegin(GL_QUADS); UInt32 i, numGlyphs = layoutResult.getNumGlyphs(); Real32 width, height; for(i = 0; i < numGlyphs; ++i) { const TextTXFGlyph *glyph = TheFont->getTXFGlyph(layoutResult.indices[i]); width = glyph->getWidth(); height = glyph->getHeight(); // No need to draw invisible glyphs if ((width <= 0.f) || (height <= 0.f)) continue; // Calculate coordinates const Vec2f &pos = layoutResult.positions[i]; Real32 posLeft = pos.x(); Real32 posTop = -pos.y(); Real32 posRight = pos.x() + width; Real32 posBottom = -pos.y() + height; Real32 texCoordLeft = glyph->getTexCoord(TextTXFGlyph::COORD_LEFT); Real32 texCoordTop = glyph->getTexCoord(TextTXFGlyph::COORD_TOP); Real32 texCoordRight = glyph->getTexCoord(TextTXFGlyph::COORD_RIGHT); Real32 texCoordBottom = glyph->getTexCoord(TextTXFGlyph::COORD_BOTTOM); // lower left corner Real32 Offset(0.001); glNormal3f(0.0,0.0,1.0); glTexCoord2f(texCoordLeft, texCoordBottom); glVertex3f(posLeft, posBottom, getTextOffset()); // lower right corner glTexCoord2f(texCoordRight, texCoordBottom); glVertex3f(posRight, posBottom, getTextOffset()); // upper right corner glTexCoord2f(texCoordRight, texCoordTop); glVertex3f(posRight, posTop, getTextOffset()); // upper left corner glTexCoord2f(texCoordLeft, texCoordTop); glVertex3f(posLeft, posTop, getTextOffset()); } glEnd(); }
void TextField::paintComponent( const PaintEvent &paintEvent ) { int caretLoc = getCaretLocation(); int textLoc = getTextOffset(); Rectangle sideclip = getInnerRectangle(); sideclip = Rectangle(sideclip.getX() + getLeftPadding() , sideclip.getY() + 2,sideclip.getSize().getWidth() - getLeftPadding() - getRightPadding() + 1, sideclip.getHeight() - 4); if(isReadOnly()) { paintEvent.graphics()->drawFilledRectangle( getSizeRectangle(),frameColor); } else { paintEvent.graphics()->drawFilledRectangle( getSizeRectangle(),getBackColor()); } paintEvent.graphics()->pushClippingRect(sideclip); if(getSelectionStart() != getSelectionEnd() && (isFocused() || !isHidingSelection()) ) { Rectangle selRect = Rectangle( getSelectionLocation(), (getInnerHeight() / 2) - (getFont()->getLineHeight() / 2), getSelectionWidth(), getFont()->getLineHeight()); paintEvent.graphics()->drawFilledRectangle( selRect,getSelectionBackColor()); } paintEvent.graphics()->drawText(Point(textLoc, + ((getInnerSize().getHeight() - getFont()->getLineHeight()) / 2)),getText().c_str(), getFontColor(),getFont()); if(isFocused()) { if(isBlinking()) paintEvent.graphics()->drawLine(Point(caretLoc + 1, ((getInnerSize().getHeight() / 2) + (getFont()->getLineHeight() / 2))), Point(caretLoc + 1, ((getInnerSize().getHeight() / 2) - (getFont()->getLineHeight() / 2))), Color(0,0,0)); } paintEvent.graphics()->popClippingRect(); }
Rect2I GUIInputTool::getCharRect(UINT32 charIdx) const { Rect2I charRect = getLocalCharRect(charIdx); Vector2I textOffset = getTextOffset(); charRect.x += textOffset.x; charRect.y += textOffset.y; return charRect; }
void TextField::mouseDown( MouseEvent &mouseEvent ) { if(mouseEvent.getButton() != MOUSE_BUTTON_LEFT) { return; } dragged = false; int x = mouseEvent.getX() - getTextOffset() - getMargin(SIDE_LEFT); positionCaret(getFont()->getStringIndexFromPosition(getText(),x)); internalSelStart = getCaretPosition(); setSelection(0,0); mouseEvent.consume(); }
void TextField::mouseDrag( MouseEvent &mouseEvent ) { if(mouseEvent.getButton() != MOUSE_BUTTON_LEFT) { return; } if(!isSelectable()) { return; } dragged = true; int maxcharSkip = getMaxCharacterSkip(); maxCharacterSkip = 1; int x = mouseEvent.getX() - getTextOffset() - getMargin(SIDE_LEFT); positionCaret(getFont()->getStringIndexFromPosition(getText(),x)); setSelection(internalSelStart,getCaretPosition()); maxCharacterSkip = maxcharSkip; mouseEvent.consume(); }
void SymbolLayer::setTextOffset(PropertyValue<std::array<float, 2>> value) { if (value == getTextOffset()) return; impl->layout.textOffset.set(value); impl->observer->onLayerLayoutPropertyChanged(*this, "text-offset"); }
Vector2I GUIInputCaret::getSpriteOffset() const { return getCaretPosition(getTextOffset()); }
void TextField::setSelection( int start, int end ) { if(!isSelectable()) { if(getSelectionStart() != getSelectionEnd()) { start = 0; end = 0; } else { return; } } if(start == end) { selStart = 0; selEnd = 0; selWidth = 0; } if(start == -1 && end == -1) { start = 0; end = getTextLength(); } else if( end == -1) { end = getTextLength(); } if( start > end) { int temp = start; start = end; end = temp; } if(start < 0) { start = 0; } if( end > getTextLength() ) { end = getTextLength(); } for(std::vector<TextFieldListener*>::iterator it = tFieldListeners.begin(); it != tFieldListeners.end(); ++it) { (*it)->selectionChanged(this,start,end); } selStart = start; selEnd = end; selLength = end - start; selPos = getFont()->getTextWidth(unicodeFunctions.subStr(getText(), 0,start)) + getTextOffset(); selWidth = getFont()->getTextWidth(unicodeFunctions.subStr(getText(), start,selLength)); }
void TextField::relocateCaret() { caretLocation = getFont()->getTextWidth(unicodeFunctions.subStr(getText(), 0,getCaretPosition())) + getTextOffset(); }
void TextField::scrollToCaret(bool negetiveChange, bool reposition) { int retOffset = getLeftPadding(); int textWidth = getFont()->getTextWidth(getText()); if(textWidth < getAdjustedWidth()) { switch(getTextAlignment()) { case ALIGN_LEFT: alignOffset = 0; break; case ALIGN_CENTER: alignOffset = (getAdjustedWidth() - textWidth) / 2; break; case ALIGN_RIGHT: alignOffset = getAdjustedWidth() - textWidth; break; default: break; } } else { alignOffset = 0; } if(getTextLength() == 0 || getCaretPosition() == 0) { tOffset = retOffset; setTextOffset(retOffset + alignOffset); return; } if(reposition) { //do we need to move? if(getFont()->getTextWidth(unicodeFunctions.subStr(getText(), 0,getCaretPosition())) > -tOffset + getAdjustedWidth() + getLeftPadding() ) { //scroll to end if(getTextLength() < getCaretPosition() + getMaxCharacterSkip()) { retOffset -= solveCaretRetPos(getFont()->getTextWidth(getText()) - getAdjustedWidth(), retOffset); } else { int initialPlace = getFont()->getTextWidth(unicodeFunctions.subStr(getText(), 0, getCaretPosition() + getMaxCharacterSkip() )) - getAdjustedWidth(); retOffset -= solveCaretRetPos(initialPlace,retOffset); } tOffset = retOffset; setTextOffset(retOffset + alignOffset); return; } else if(tOffset + getFont()->getTextWidth(unicodeFunctions.subStr(getText(), 0,getCaretPosition())) <= leftPadding) { if(getCaretPosition() - getMaxCharacterSkip() > 0) { int initialPlace = getFont()->getTextWidth(unicodeFunctions.subStr(getText(), 0, getCaretPosition() - getMaxCharacterSkip() )); retOffset -= solveCaretRetPos(initialPlace,retOffset); } tOffset = retOffset; setTextOffset(retOffset + alignOffset); return; } else if(negetiveChange ) { int change = getCaretLocation() - getFont()->getTextWidth(unicodeFunctions.subStr(getText(), 0, getCaretPosition() )) ; if(change <= getLeftPadding()) { tOffset = change; setTextOffset(change); } else { tOffset = leftPadding; setTextOffset(leftPadding + alignOffset); } return; } } //if there is more text than width //but theres not enough to fill the width //then fill the width int a = getAdjustedWidth() + getLeftPadding(); int b = getTextOffset() + textWidth; if(a > b && getTextOffset() < getLeftPadding()) { retOffset = -textWidth + getInnerSize().getWidth() - getRightPadding(); tOffset = retOffset; } else if(getTextOffset() >= getLeftPadding() ) { tOffset = leftPadding; setTextOffset(leftPadding + alignOffset); return; } setTextOffset(tOffset + alignOffset); }