mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-18 06:55:48 +03:00
Line Wrapping more basic logic.
This commit is contained in:
@@ -38,6 +38,8 @@ class FontStyleConfig {
|
||||
OutlineColor == other.OutlineColor;
|
||||
}
|
||||
|
||||
bool operator!=( const FontStyleConfig& other ) { return !( *this == other ); }
|
||||
|
||||
virtual void updateFontStyleConfig( const FontStyleConfig& fontStyleConfig ) {
|
||||
Font = fontStyleConfig.Font;
|
||||
Style = fontStyleConfig.Style;
|
||||
|
||||
@@ -10,16 +10,27 @@ using namespace EE::UI::Doc;
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
enum class LineWrapMode { Letter, Word };
|
||||
enum class LineWrapMode { NoWrap, Letter, Word };
|
||||
|
||||
struct LineWrapInfo {
|
||||
std::vector<size_t> wraps;
|
||||
Float paddingStart;
|
||||
bool hasWraps() const { return !wraps.empty(); }
|
||||
std::vector<Int64> wraps;
|
||||
Float paddingStart{ 0.f };
|
||||
};
|
||||
|
||||
class LineWrapping {
|
||||
class EE_API LineWrapping {
|
||||
public:
|
||||
struct Config {
|
||||
LineWrapMode mode{ LineWrapMode::NoWrap };
|
||||
bool keepIndentation{ true };
|
||||
Uint32 tabWidth{ 4 };
|
||||
std::optional<Uint32> maxCharactersWidth;
|
||||
bool operator==( const Config& other ) {
|
||||
return mode == other.mode && keepIndentation == other.keepIndentation &&
|
||||
tabWidth == other.tabWidth && maxCharactersWidth == other.maxCharactersWidth;
|
||||
}
|
||||
bool operator!=( const Config& other ) { return !(*this == other); }
|
||||
};
|
||||
|
||||
static LineWrapInfo computeLineBreaks( const String& string, const FontStyleConfig& fontStyle,
|
||||
Float maxWidth, LineWrapMode mode, bool keepIndentation,
|
||||
Uint32 tabWidth = 4 );
|
||||
@@ -29,10 +40,32 @@ class LineWrapping {
|
||||
LineWrapMode mode, bool keepIndentation,
|
||||
Uint32 tabWidth = 4 );
|
||||
|
||||
LineWrapping( std::shared_ptr<TextDocument> doc, FontStyleConfig fontStyle, Config config );
|
||||
|
||||
size_t getTotalLines() const;
|
||||
|
||||
const Config& config() const { return mConfig; }
|
||||
|
||||
void reconstructBreaks();
|
||||
|
||||
void updateBreaks( Int64 fromLine, Int64 toLine, Int64 numLines );
|
||||
|
||||
void setConfig( Config config );
|
||||
|
||||
void setMaxWidth( Float maxWidth );
|
||||
|
||||
void setFontStyle( FontStyleConfig fontStyle );
|
||||
|
||||
protected:
|
||||
std::shared_ptr<TextDocument> mDoc;
|
||||
FontStyleConfig mFontStyle;
|
||||
Config mConfig;
|
||||
Float mMaxWidth{ 0 };
|
||||
std::unordered_map<Int64, TextPosition> mWrappedLines;
|
||||
std::unordered_map<Int64, Int64> mWrappedLineToIndex;
|
||||
std::vector<TextPosition> mWrappedLines;
|
||||
std::vector<Float> mWrappedLinesOffset;
|
||||
std::vector<Int64> mWrappedLineToIndex;
|
||||
|
||||
Int64 toWrappedIndex( Int64 docIdx, bool retLast );
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -10,7 +10,8 @@ LineWrapInfo LineWrapping::computeLineBreaks( const String& string,
|
||||
LineWrapMode mode, bool keepIndentation,
|
||||
Uint32 tabWidth ) {
|
||||
LineWrapInfo info;
|
||||
if ( string.empty() || nullptr == fontStyle.Font )
|
||||
info.wraps.push_back( 0 );
|
||||
if ( string.empty() || nullptr == fontStyle.Font || mode == LineWrapMode::NoWrap )
|
||||
return info;
|
||||
|
||||
if ( keepIndentation ) {
|
||||
@@ -49,7 +50,7 @@ LineWrapInfo LineWrapping::computeLineBreaks( const String& string,
|
||||
else if ( ( curChar ) == '\r' )
|
||||
w = 0;
|
||||
|
||||
if ( curChar != '\r' && !isMonospace ) {
|
||||
if ( !isMonospace && curChar != '\r' ) {
|
||||
w += fontStyle.Font->getKerning( prevChar, curChar, fontStyle.CharacterSize, bold,
|
||||
italic, outlineThickness );
|
||||
prevChar = curChar;
|
||||
@@ -82,13 +83,15 @@ LineWrapInfo LineWrapping::computeLineBreaks( const TextDocument& doc, size_t li
|
||||
const FontStyleConfig& fontStyle, Float maxWidth,
|
||||
LineWrapMode mode, bool keepIndentation,
|
||||
Uint32 tabWidth ) {
|
||||
if ( nullptr == fontStyle.Font || fontStyle.Font->isMonospace() ||
|
||||
nullptr == doc.getHighlighter() || doc.getSyntaxDefinition().getPatterns().empty() ) {
|
||||
if ( nullptr == fontStyle.Font || mode == LineWrapMode::NoWrap ||
|
||||
fontStyle.Font->isMonospace() || nullptr == doc.getHighlighter() ||
|
||||
doc.getSyntaxDefinition().getPatterns().empty() ) {
|
||||
return computeLineBreaks( doc.line( line ).getText(), fontStyle, maxWidth, mode,
|
||||
keepIndentation, tabWidth );
|
||||
}
|
||||
|
||||
LineWrapInfo info;
|
||||
info.wraps.push_back( 0 );
|
||||
const auto& string = doc.line( line ).getText();
|
||||
const auto& tokens = doc.getHighlighter()->getLine( line );
|
||||
|
||||
@@ -167,4 +170,128 @@ LineWrapInfo LineWrapping::computeLineBreaks( const TextDocument& doc, size_t li
|
||||
return info;
|
||||
}
|
||||
|
||||
LineWrapping::LineWrapping( std::shared_ptr<TextDocument> doc, FontStyleConfig fontStyle,
|
||||
Config config ) :
|
||||
mDoc( std::move( doc ) ),
|
||||
mFontStyle( std::move( fontStyle ) ),
|
||||
mConfig( std::move( config ) ) {}
|
||||
|
||||
void LineWrapping::setMaxWidth( Float maxWidth ) {
|
||||
if ( maxWidth != mMaxWidth ) {
|
||||
mMaxWidth = maxWidth;
|
||||
reconstructBreaks();
|
||||
}
|
||||
}
|
||||
|
||||
void LineWrapping::setFontStyle( FontStyleConfig fontStyle ) {
|
||||
if ( fontStyle != mFontStyle ) {
|
||||
mFontStyle = std::move( fontStyle );
|
||||
reconstructBreaks();
|
||||
}
|
||||
}
|
||||
|
||||
void LineWrapping::setConfig( Config config ) {
|
||||
if ( config != mConfig ){
|
||||
mConfig = std::move( config );
|
||||
reconstructBreaks();
|
||||
}
|
||||
}
|
||||
|
||||
void LineWrapping::reconstructBreaks() {
|
||||
if ( 0 == mMaxWidth )
|
||||
return;
|
||||
|
||||
mWrappedLines.clear();
|
||||
mWrappedLineToIndex.clear();
|
||||
mWrappedLinesOffset.clear();
|
||||
|
||||
size_t linesCount = mDoc->linesCount();
|
||||
mWrappedLines.reserve( linesCount * 2 );
|
||||
mWrappedLinesOffset.reserve( linesCount );
|
||||
|
||||
for ( auto i = 0; i < linesCount; i++ ) {
|
||||
auto lb = computeLineBreaks( *mDoc, i, mFontStyle, mMaxWidth, mConfig.mode,
|
||||
mConfig.keepIndentation, mConfig.tabWidth );
|
||||
mWrappedLinesOffset.emplace_back( lb.paddingStart );
|
||||
for ( const auto& col : lb.wraps )
|
||||
mWrappedLines.emplace_back( i, col );
|
||||
}
|
||||
|
||||
std::optional<Int64> lastWrap;
|
||||
size_t i = 0;
|
||||
mWrappedLineToIndex.reserve( linesCount );
|
||||
|
||||
for ( const auto& wl : mWrappedLines ) {
|
||||
if ( !lastWrap || *lastWrap != wl.line() ) {
|
||||
mWrappedLineToIndex.emplace_back( i );
|
||||
lastWrap = wl.line();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
Int64 LineWrapping::toWrappedIndex( Int64 docIdx, bool retLast ) {
|
||||
auto idx = mWrappedLineToIndex[docIdx < 0 ? 0
|
||||
: ( docIdx >= mWrappedLineToIndex.size()
|
||||
? mWrappedLineToIndex.size() - 1
|
||||
: docIdx )];
|
||||
if ( retLast ) {
|
||||
Int64 lastOfLine = mWrappedLines[idx].line();
|
||||
for ( auto i = idx + 1; i < mWrappedLines.size(); i++ ) {
|
||||
if ( mWrappedLines[i].line() == lastOfLine )
|
||||
idx = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
void LineWrapping::updateBreaks( Int64 fromLine, Int64 toLine, Int64 numLines ) {
|
||||
// Get affected wrapped range
|
||||
Int64 oldIdxFrom = toWrappedIndex( fromLine, false );
|
||||
Int64 oldIdxTo = toWrappedIndex( toLine, true );
|
||||
|
||||
// Remove old wrapped lines
|
||||
mWrappedLines.erase( mWrappedLines.begin() + oldIdxFrom, mWrappedLines.begin() + oldIdxTo );
|
||||
|
||||
// Remove old offsets
|
||||
mWrappedLinesOffset.erase( mWrappedLinesOffset.begin() + fromLine,
|
||||
mWrappedLinesOffset.begin() + toLine );
|
||||
|
||||
// Shift the line numbers
|
||||
if ( numLines != 0 ) {
|
||||
Int64 wrappedLines = mWrappedLines.size();
|
||||
for ( Int64 i = oldIdxFrom; i < wrappedLines; i++ )
|
||||
mWrappedLines[i].setLine( mWrappedLines[i].line() + numLines );
|
||||
}
|
||||
|
||||
// Recompute line breaks
|
||||
for ( auto i = fromLine; i <= toLine; i++ ) {
|
||||
auto lb = computeLineBreaks( *mDoc, i, mFontStyle, mMaxWidth, mConfig.mode,
|
||||
mConfig.keepIndentation, mConfig.tabWidth );
|
||||
mWrappedLinesOffset.insert( mWrappedLinesOffset.begin() + i, lb.paddingStart );
|
||||
Int64 loffset = 0;
|
||||
for ( const auto& col : lb.wraps ) {
|
||||
mWrappedLines.insert( mWrappedLines.begin() + i + loffset, { i, col } );
|
||||
loffset++;
|
||||
}
|
||||
}
|
||||
|
||||
// Recompute wrapped line to index
|
||||
Int64 line = fromLine;
|
||||
Int64 wrappedLines = mWrappedLines.size();
|
||||
for ( Int64 wrappedIdx = oldIdxFrom; wrappedIdx < wrappedLines; wrappedIdx++ ) {
|
||||
if ( mWrappedLines[wrappedIdx].column() == 0 ) {
|
||||
mWrappedLineToIndex[line] = wrappedIdx;
|
||||
line++;
|
||||
}
|
||||
}
|
||||
mWrappedLineToIndex.resize( mDoc->linesCount() );
|
||||
}
|
||||
|
||||
size_t LineWrapping::getTotalLines() const {
|
||||
return mConfig.mode == LineWrapMode::NoWrap ? mDoc->linesCount() : mWrappedLines.size();
|
||||
}
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
Reference in New Issue
Block a user