| 2569 | } |
| 2570 | |
| 2571 | Vector2d UICodeEditor::getTextPositionOffset( const TextPosition& position, |
| 2572 | std::optional<Float> lineHeight, |
| 2573 | bool allowVisualLineEnd, |
| 2574 | bool visualizeNewLine ) const { |
| 2575 | double lh = lineHeight ? *lineHeight : getLineHeight(); |
| 2576 | if ( mDocView.isWrappedLine( position.line() ) ) { |
| 2577 | auto info = mDocView.getVisibleLineRange( position, allowVisualLineEnd ); |
| 2578 | auto firstWrappedIndex = mDocView.toVisibleIndex( position.line() ); |
| 2579 | Float offsetX = |
| 2580 | ( info.visibleIndex != firstWrappedIndex ? mDocView.getLinePadding( position.line() ) |
| 2581 | : 0.f ); |
| 2582 | double offsetY = mDocView.getLineYOffset( info.visibleIndex, lh ); |
| 2583 | if ( !isMonospaceLine( position.line() ) ) { |
| 2584 | if ( !info.range.isValid() ) |
| 2585 | return {}; |
| 2586 | const auto& line = mDoc->line( position.line() ).getText(); |
| 2587 | auto partialLine = |
| 2588 | line.view().substr( info.range.start().column(), info.range.end().column() ); |
| 2589 | Float x = |
| 2590 | Text::findCharacterPos( |
| 2591 | position.column() - info.range.start().column(), mFont, getCharacterSize(), |
| 2592 | partialLine, mFontStyleConfig.Style, mTabWidth, |
| 2593 | mFontStyleConfig.OutlineThickness, mTabStops ? 0 : std::optional<Float>(), |
| 2594 | false, mDoc->line( position.line() ).getTextHints() | getWidgetTextDrawHints(), |
| 2595 | mTextDirection ) |
| 2596 | .x; |
| 2597 | if ( visualizeNewLine && allowVisualLineEnd && |
| 2598 | position.column() == (Int64)mDoc->line( position.line() ).getText().size() - 1 ) |
| 2599 | x += getGlyphWidth(); |
| 2600 | return { x + offsetX, offsetY }; |
| 2601 | } |
| 2602 | const String& line = mDoc->line( position.line() ).getText(); |
| 2603 | Float glyphWidth = getGlyphWidth(); |
| 2604 | Float x = 0; |
| 2605 | Int64 maxCol = eemin( position.column(), info.range.end().column() ); |
| 2606 | for ( auto i = info.range.start().column(); i < maxCol; i++ ) { |
| 2607 | if ( line[i] == '\t' ) { |
| 2608 | x += Text::tabAdvance( glyphWidth, mTabWidth, |
| 2609 | mTabStops ? x : std::optional<Float>{} ); |
| 2610 | } else if ( visualizeNewLine || ( line[i] != '\n' && line[i] != '\r' ) ) { |
| 2611 | x += glyphWidth; |
| 2612 | } |
| 2613 | } |
| 2614 | if ( visualizeNewLine && allowVisualLineEnd && |
| 2615 | position.column() == (Int64)mDoc->line( position.line() ).getText().size() - 1 ) |
| 2616 | x += glyphWidth; |
| 2617 | return { x + offsetX, offsetY }; |
| 2618 | } |
| 2619 | |
| 2620 | double offsetY = mDocView.getLineYOffset( position.line(), lh ); |
| 2621 | if ( !isMonospaceLine( position.line() ) ) { |
| 2622 | bool isLastChar = |
| 2623 | position.column() == (Int64)mDoc->line( position.line() ).getText().size(); |
| 2624 | Float x = |
| 2625 | Text::findCharacterPos( |
| 2626 | isLastChar ? position.column() - 1 : position.column(), mFont, getCharacterSize(), |
| 2627 | mDoc->line( position.line() ).getText(), mFontStyleConfig.Style, mTabWidth, |
| 2628 | mFontStyleConfig.OutlineThickness, mTabStops ? 0 : std::optional<Float>(), false, |
no test coverage detected