| 179 | } |
| 180 | |
| 181 | void computeCursorPositions() |
| 182 | { |
| 183 | cursorPositions.clear(); |
| 184 | |
| 185 | const auto globalBounds = text.getGlobalBounds(); |
| 186 | const auto& shapedGlyphs = text.getShapedGlyphs(); |
| 187 | const auto ascent = font->getAscent(text.getCharacterSize()); |
| 188 | const auto descent = font->getDescent(text.getCharacterSize()); |
| 189 | auto previousCluster = 0u; |
| 190 | sf::Vector2f previousClusterPosition; |
| 191 | sf::Vector2f previousClusterSize; |
| 192 | float previousClusterAdvance{}; |
| 193 | sf::Text::TextDirection previousClusterDirection{}; |
| 194 | |
| 195 | // Set size of cursor depending on text orientation |
| 196 | if (text.getTextOrientation() == sf::Text::TextOrientation::Default) |
| 197 | { |
| 198 | // Horizontal (Vertical cursor) |
| 199 | cursor.setSize({1.0f, ascent - descent}); |
| 200 | } |
| 201 | else |
| 202 | { |
| 203 | // Vertical (Horizontal cursor) |
| 204 | // In this example we don't do anything fancy and just set the cursor width to the width of the bounds |
| 205 | cursor.setSize({globalBounds.size.x, 1.0f}); |
| 206 | } |
| 207 | |
| 208 | for (const auto& shapedGlyph : shapedGlyphs) |
| 209 | { |
| 210 | // Combining marks can't be valid cursor positions so |
| 211 | // we just skip over trailing glyphs that share the same |
| 212 | // cluster value as the base glyph that preceeds them |
| 213 | if (previousCluster != 0u && shapedGlyph.cluster == previousCluster) |
| 214 | continue; |
| 215 | |
| 216 | sf::Vector2f clusterPosition{shapedGlyph.position.x, shapedGlyph.baseline - ascent}; |
| 217 | |
| 218 | // Remember that in RTL text, the "before grapheme position" is to the right of the glyph |
| 219 | if (shapedGlyph.textDirection == sf::Text::TextDirection::RightToLeft) |
| 220 | clusterPosition.x += shapedGlyph.glyph.bounds.size.x; |
| 221 | |
| 222 | const auto isVerticalWhitespace = shapedGlyph.glyph.bounds.size.x == 0.0f; |
| 223 | |
| 224 | // For vertical orientations, the "before grapheme position" is to the top/bottom of the glyph |
| 225 | if (shapedGlyph.textDirection == sf::Text::TextDirection::TopToBottom) |
| 226 | { |
| 227 | clusterPosition = sf::Vector2f{shapedGlyph.position.x + |
| 228 | (shapedGlyph.glyph.bounds.size.x - globalBounds.size.x) / 2.0f, |
| 229 | shapedGlyph.position.y - |
| 230 | (isVerticalWhitespace ? shapedGlyph.glyph.bounds.size.y / 2.0f : ascent)}; |
| 231 | } |
| 232 | else if (shapedGlyph.textDirection == sf::Text::TextDirection::BottomToTop) |
| 233 | { |
| 234 | clusterPosition = sf::Vector2f{shapedGlyph.position.x + |
| 235 | (shapedGlyph.glyph.bounds.size.x - globalBounds.size.x) / 2.0f, |
| 236 | shapedGlyph.position.y - |
| 237 | (isVerticalWhitespace ? -shapedGlyph.glyph.bounds.size.y / 2.0f : descent)}; |
| 238 | } |
nothing calls this directly
no test coverage detected