More improvements to the UICodeEditor and TextDocument.

Improved the SyntaxHighligther.
This commit is contained in:
Martín Lucas Golini
2020-05-26 05:48:22 -03:00
parent c79cae664a
commit 2de37d3a45
12 changed files with 1986 additions and 102 deletions

View File

@@ -614,6 +614,8 @@ Probably deprecate the Maps module, since I will focus my efforts on the UI syst
* Jason Perkins for [premake](https://premake.github.io/)
* Daniel Bahr for [CRC++](https://github.com/d-bahr/CRCpp)
* Martín Lucas Golini ( me ) and all the several contributors for [SOIL2](https://github.com/SpartanJ/SOIL2) and [efsw](https://github.com/SpartanJ/efsw)
* The Xiph open source community for [libogg](https://xiph.org/ogg/) and [libvorbis](https://xiph.org/vorbis/)

View File

@@ -449,7 +449,7 @@ class EE_API String {
** @param index Index of the character to get
** @return Character at position \a index
**/
StringBaseType operator[]( std::size_t index ) const;
const StringBaseType& operator[]( std::size_t index ) const;
/** @brief Overload of [] operator to access a character by its position
** This function provides read and write access to characters.
@@ -465,7 +465,7 @@ class EE_API String {
*actual position in the string.
** @return The character at position pos in the string.
*/
StringBaseType at( std::size_t index ) const;
const StringBaseType& at( std::size_t index ) const;
/** @brief clear the string
** This function removes all the characters from the string.

View File

@@ -9,7 +9,7 @@ namespace EE { namespace UI { namespace Doc {
struct TokenizedLine {
int initState;
String text;
Uint32 hash;
std::vector<SyntaxToken> tokens;
int state;
};
@@ -20,11 +20,21 @@ class EE_API SyntaxHighlighter {
void reset();
void invalidate( Int64 lineIndex );
const std::vector<SyntaxToken>& getLine( const size_t& index );
Int64 getFirstInvalidLine() const;
Int64 getMaxWantedLine() const;
bool updateDirty( int visibleLinesCount = 40 );
protected:
TextDocument* mDoc;
std::map<size_t, TokenizedLine> mLines;
Int64 mFirstInvalidLine;
Int64 mMaxWantedLine;
TokenizedLine tokenizeLine( const size_t& line, const int& state );
};

View File

@@ -16,6 +16,63 @@ using namespace EE::System;
namespace EE { namespace UI { namespace Doc {
class EE_API TextDocumentLine {
public:
TextDocumentLine( const String& text ) : mText( text ) { updateHash(); }
void setText( const String& text ) {
mText = text;
updateHash();
}
const String& getText() const { return mText; }
void operator=( const std::string& right ) { setText( right ); }
String::StringBaseType operator[]( std::size_t index ) const { return mText[index]; }
void insertChar( const unsigned int& pos, const String::StringBaseType& tchar ) {
mText.insert( mText.begin() + pos, tchar );
updateHash();
}
void append( const String& text ) {
mText.append( text );
updateHash();
}
void append( const String::StringBaseType& code ) {
mText.append( code );
updateHash();
}
String substr( std::size_t pos = 0, std::size_t n = String::StringType::npos ) const {
return mText.substr( pos, n );
}
String::Iterator insert( String::Iterator p, const String::StringBaseType& c ) {
auto it = mText.insert( p, c );
updateHash();
return it;
}
bool empty() const { return mText.empty(); }
size_t size() const { return mText.size(); }
size_t length() const { return mText.length(); }
const Uint32& getHash() const { return mHash; }
std::string toUtf8() const { return mText.toUtf8(); }
protected:
String mText;
Uint32 mHash;
void updateHash() { mHash = mText.getHash(); }
};
class EE_API TextDocument {
public:
class EE_API Client {
@@ -26,6 +83,7 @@ class EE_API TextDocument {
virtual void onDocumentSelectionChange( const TextRange& ) = 0;
virtual void onDocumentLineCountChange( const size_t& lastCount,
const size_t& newCount ) = 0;
virtual void onDocumentLineChanged( const Int64& lineIndex ) = 0;
};
enum IndentType { IndentSpaces, IndentTabs };
@@ -56,13 +114,13 @@ class EE_API TextDocument {
const TextRange& getSelection() const;
String& line( const size_t& index );
TextDocumentLine& line( const size_t& index );
const String& line( const size_t& index ) const;
const TextDocumentLine& line( const size_t& index ) const;
size_t linesCount() const;
std::vector<String>& lines();
std::vector<TextDocumentLine>& lines();
bool hasSelection() const;
@@ -219,7 +277,7 @@ class EE_API TextDocument {
friend class UndoStack;
UndoStack mUndoStack;
std::string mFilePath;
std::vector<String> mLines;
std::vector<TextDocumentLine> mLines;
TextRange mSelection;
std::unordered_set<Client*> mClients;
bool mIsCLRF{false};
@@ -241,9 +299,11 @@ class EE_API TextDocument {
void notifyLineCountChanged( const size_t& lastCount, const size_t& newCount );
void insertAtStartOfSelectedLines( String text, bool skipEmpty );
void notifyLineChanged( const Int64& lineIndex );
void removeFromStartOfSelectedLines( String text, bool skipEmpty );
void insertAtStartOfSelectedLines( const String& text, bool skipEmpty );
void removeFromStartOfSelectedLines( const String& text, bool skipEmpty );
void remove( TextRange range, UndoStackContainer& undoStack, const Time& time );

View File

@@ -112,6 +112,10 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
virtual Float getColXOffset( TextPosition position );
const bool& isLocked() const;
void setLocked( bool locked );
protected:
struct LastXOffset {
TextPosition position;
@@ -126,6 +130,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
bool mCursorVisible;
bool mMouseDown;
bool mShowLineNumber;
bool mLocked;
Uint32 mTabWidth;
Int64 mLastColOffset;
Vector2f mScroll;
@@ -176,6 +181,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
void onDocumentLineCountChange( const size_t& lastCount, const size_t& newCount );
void onDocumentLineChanged( const Int64& lineIndex );
std::pair<int, int> getVisibleLineRange();
int getVisibleLinesCount();

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.12.0, 2020-05-25T19:14:39. -->
<!-- Written by QtCreator 4.12.0, 2020-05-26T05:47:23. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>

View File

@@ -4,6 +4,9 @@
#include <eepp/core/string.hpp>
#include <eepp/core/utf.hpp>
#include <iterator>
#include <crc/CRC.h>
static CRC::Table<std::uint32_t, 32> CRC_TABLE(CRC::CRC_32());
namespace EE {
@@ -29,7 +32,7 @@ Uint32 String::hash( const std::string& str ) {
}
Uint32 String::hash( const String& str ) {
return String::hash( (const Uint8*)str.c_str() );
return CRC::Calculate( (void*)str.c_str(), sizeof(StringBaseType)*str.size(), CRC_TABLE );
}
bool String::isCharacter( const int& value ) {
@@ -594,7 +597,7 @@ String& String::operator+=( const StringBaseType& right ) {
return *this;
}
String::StringBaseType String::operator[]( std::size_t index ) const {
const String::StringBaseType& String::operator[]( std::size_t index ) const {
return mString[index];
}
@@ -602,7 +605,7 @@ String::StringBaseType& String::operator[]( std::size_t index ) {
return mString[index];
}
String::StringBaseType String::at( std::size_t index ) const {
const String::StringBaseType& String::at( std::size_t index ) const {
return mString.at( index );
}

View File

@@ -3,29 +3,37 @@
namespace EE { namespace UI { namespace Doc {
SyntaxHighlighter::SyntaxHighlighter( TextDocument* doc ) : mDoc( doc ) {
SyntaxHighlighter::SyntaxHighlighter( TextDocument* doc ) :
mDoc( doc ), mFirstInvalidLine( 0 ), mMaxWantedLine( 0 ) {
reset();
}
void SyntaxHighlighter::reset() {
mLines.clear();
mFirstInvalidLine = 0;
mMaxWantedLine = 0;
}
void SyntaxHighlighter::invalidate( Int64 lineIndex ) {
mFirstInvalidLine = lineIndex;
mMaxWantedLine = eemin<Int64>( mMaxWantedLine, (Int64)mDoc->linesCount() - 1 );
}
TokenizedLine SyntaxHighlighter::tokenizeLine( const size_t& line, const int& state ) {
TokenizedLine tokenizedLine;
tokenizedLine.initState = state;
tokenizedLine.text = mDoc->line( line );
tokenizedLine.hash = mDoc->line( line ).getHash();
std::pair<std::vector<SyntaxToken>, int> res = SyntaxTokenizer::tokenize(
mDoc->getSyntaxDefinition(), tokenizedLine.text.toUtf8(), state );
mDoc->getSyntaxDefinition(), mDoc->line( line ).toUtf8(), state );
tokenizedLine.tokens = std::move( res.first );
tokenizedLine.state = std::move( res.second );
return tokenizedLine;
}
const std::vector<SyntaxToken>& SyntaxHighlighter::getLine( const size_t& index ) {
auto it = mLines.find( index );
const auto& it = mLines.find( index );
if ( it == mLines.end() ||
( index < mDoc->linesCount() && mDoc->line( index ) != it->second.text ) ) {
( index < mDoc->linesCount() && mDoc->line( index ).getHash() != it->second.hash ) ) {
int prevState = SYNTAX_TOKENIZER_STATE_NONE;
if ( index > 0 ) {
auto prevIt = mLines.find( index - 1 );
@@ -36,7 +44,44 @@ const std::vector<SyntaxToken>& SyntaxHighlighter::getLine( const size_t& index
mLines[index] = tokenizeLine( index, prevState );
return mLines[index].tokens;
}
mMaxWantedLine = eemax<Int64>( mMaxWantedLine, index );
return it->second.tokens;
}
Int64 SyntaxHighlighter::getFirstInvalidLine() const {
return mFirstInvalidLine;
}
Int64 SyntaxHighlighter::getMaxWantedLine() const {
return mMaxWantedLine;
}
bool SyntaxHighlighter::updateDirty( int visibleLinesCount ) {
if ( mFirstInvalidLine > mMaxWantedLine ) {
mMaxWantedLine = 0;
} else {
bool changed = false;
Int64 max = eemin( mFirstInvalidLine + visibleLinesCount, mMaxWantedLine );
for ( Int64 index = mFirstInvalidLine; index <= max; index++ ) {
int state = SYNTAX_TOKENIZER_STATE_NONE;
if ( index > 0 ) {
auto prevIt = mLines.find( index - 1 );
if ( prevIt != mLines.end() ) {
state = prevIt->second.state;
}
}
const auto& it = mLines.find( index );
if ( it != mLines.end() && it->second.initState != state ) {
mLines[index] = tokenizeLine( index, state );
changed = true;
}
}
mFirstInvalidLine = max + 1;
return changed;
}
return false;
}
}}} // namespace EE::UI::Doc

View File

@@ -62,13 +62,13 @@ void TextDocument::loadFromPath( const std::string& path ) {
line = line.substr( 0, line.size() - 1 );
mIsCLRF = true;
}
mLines.emplace_back( String( line + "\n" ) );
mLines.emplace_back( TextDocumentLine( line + "\n" ) );
}
if ( mLines.empty() ) {
mLines.emplace_back( String( "\n" ) );
mLines.emplace_back( TextDocumentLine( "\n" ) );
} else if ( mLines[mLines.size() - 1][mLines[mLines.size() - 1].size() - 1] != '\n' ) {
mLines[mLines.size() - 1] += '\n';
mLines[mLines.size() - 1].append( '\n' );
}
}
@@ -93,9 +93,8 @@ bool TextDocument::save( IOStreamFile& stream, const bool& utf8bom ) {
}
size_t lastLine = mLines.size() - 1;
for ( size_t i = 0; i <= lastLine; i++ ) {
String& line = mLines[i];
std::string utf8( line.toUtf8() );
if ( i == lastLine && line.size() > 1 ) {
std::string utf8( mLines[i].toUtf8() );
if ( i == lastLine && utf8.size() > 1 && utf8[utf8.size() - 1] == '\n' ) {
// Last \n is added by the document but it's not part of the document.
utf8.pop_back();
}
@@ -160,11 +159,11 @@ const TextRange& TextDocument::getSelection() const {
return mSelection;
}
String& TextDocument::line( const size_t& index ) {
TextDocumentLine& TextDocument::line( const size_t& index ) {
return mLines[index];
}
const String& TextDocument::line( const size_t& index ) const {
const TextDocumentLine& TextDocument::line( const size_t& index ) const {
return mLines[index];
}
@@ -172,7 +171,7 @@ size_t TextDocument::linesCount() const {
return mLines.size();
}
std::vector<String>& TextDocument::lines() {
std::vector<TextDocumentLine>& TextDocument::lines() {
return mLines;
}
@@ -188,7 +187,7 @@ String TextDocument::getText( const TextRange& range ) const {
}
std::vector<String> lines = {mLines[nrange.start().line()].substr( nrange.start().column() )};
for ( auto i = nrange.start().line() + 1; i <= nrange.end().line() - 1; i++ ) {
lines.emplace_back( mLines[i] );
lines.emplace_back( mLines[i].getText() );
}
lines.emplace_back( mLines[nrange.end().line()].substr( 0, nrange.end().column() ) );
return String::join( lines, -1 );
@@ -240,27 +239,30 @@ TextPosition TextDocument::insert( TextPosition position, const String::StringBa
for ( size_t i = position.column(); i < line( row ).length(); i++ )
line_content.append( line( row )[i] );
mLines.insert( mLines.begin() + position.line() + ( atTail ? 1 : 0 ), String( "\n" ) );
notifyLineChanged( position.line() );
return atTail
? TextPosition( position.line() + 1, line( position.line() + 1 ).length() )
: TextPosition( position.line() + 1, 0 );
}
String newLine =
line( position.line() )
.substr( position.column(), line( position.line() ).length() - position.column() );
String& oldLine = line( position.line() );
oldLine = line( position.line() ).substr( 0, position.column() );
TextDocumentLine newLine( line( position.line() )
.substr( position.column(), line( position.line() ).length() -
position.column() ) );
TextDocumentLine& oldLine = line( position.line() );
oldLine.setText( line( position.line() ).substr( 0, position.column() ) );
// TODO: Investigate why this is needed when undo is used.
// This fixes the case when a line ends up without an \n at the end of it.
if ( oldLine.empty() || oldLine[oldLine.size() - 1] != '\n' ) {
oldLine += '\n';
oldLine.append( '\n' );
}
if ( newLine.empty() || newLine[newLine.size() - 1] != '\n' ) {
newLine += '\n';
newLine.append( '\n' );
}
mLines.insert( mLines.begin() + position.line() + 1, std::move( newLine ) );
notifyLineChanged( position.line() );
return {position.line() + 1, 0};
}
line( position.line() ).insert( line( position.line() ).begin() + position.column(), ch );
line( position.line() ).insertChar( position.column(), ch );
notifyLineChanged( position.line() );
return {position.line(), position.column() + 1};
}
@@ -295,7 +297,7 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const
if ( range.start().line() == range.end().line() ) {
// Delete within same line.
String& line = this->line( range.start().line() );
TextDocumentLine& line = this->line( range.start().line() );
bool wholeLineIsSelected =
range.start().column() == 0 && range.end().column() == (Int64)line.length();
@@ -313,13 +315,13 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const
if ( afterSelection.empty() || afterSelection[afterSelection.size() - 1] != '\n' )
afterSelection += '\n';
line.assign( beforeSelection + afterSelection );
line.setText( beforeSelection + afterSelection );
}
} else {
// Delete across a newline, merging lines.
eeASSERT( range.start().line() == range.end().line() - 1 );
auto& firstLine = line( range.start().line() );
auto& secondLine = line( range.end().line() );
TextDocumentLine& firstLine = line( range.start().line() );
TextDocumentLine& secondLine = line( range.end().line() );
auto beforeSelection = firstLine.substr( 0, range.start().column() );
auto afterSelection = !secondLine.empty()
? secondLine.substr( range.end().column(),
@@ -331,7 +333,7 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const
if ( afterSelection.empty() || afterSelection[afterSelection.size() - 1] != '\n' )
afterSelection += '\n';
firstLine.assign( beforeSelection + afterSelection );
firstLine.setText( beforeSelection + afterSelection );
mLines.erase( mLines.begin() + range.end().line() );
}
@@ -339,6 +341,7 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const
mLines.emplace_back( String( "\n" ) );
}
notifyTextChanged();
notifyLineChanged( range.start().line() );
}
TextPosition TextDocument::positionOffset( TextPosition position, int columnOffset ) const {
@@ -647,7 +650,7 @@ void TextDocument::newLine() {
String input( "\n" );
TextPosition start = getSelection().start();
if ( start.line() >= 0 && start.line() < (Int64)mLines.size() ) {
String& ln = line( start.line() );
const String& ln = line( start.line() ).getText();
size_t to = eemin<size_t>( ln.size(), start.column() );
int indent = 0;
for ( size_t i = 0; i < to; i++ ) {
@@ -664,12 +667,12 @@ void TextDocument::newLine() {
textInput( input );
}
void TextDocument::insertAtStartOfSelectedLines( String text, bool skipEmpty ) {
void TextDocument::insertAtStartOfSelectedLines( const String& text, bool skipEmpty ) {
TextPosition prevStart = getSelection().start();
TextRange range = getSelection( true );
bool swap = prevStart != range.start();
for ( auto i = range.start().line(); i <= range.end().line(); i++ ) {
const String& line = this->line( i );
const String& line = this->line( i ).getText();
if ( !skipEmpty || line.length() != 1 ) {
insert( {i, 0}, text );
}
@@ -678,12 +681,12 @@ void TextDocument::insertAtStartOfSelectedLines( String text, bool skipEmpty ) {
TextPosition( range.end().line(), range.end().column() + text.size() ), swap );
}
void TextDocument::removeFromStartOfSelectedLines( String text, bool skipEmpty ) {
void TextDocument::removeFromStartOfSelectedLines( const String& text, bool skipEmpty ) {
TextPosition prevStart = getSelection().start();
TextRange range = getSelection( true );
bool swap = prevStart != range.start();
for ( auto i = range.start().line(); i <= range.end().line(); i++ ) {
const String& line = this->line( i );
const String& line = this->line( i ).getText();
if ( !skipEmpty || line.length() != 1 ) {
if ( line.substr( 0, text.length() ) == text ) {
remove( {{i, 0}, {i, static_cast<Int64>( text.length() )}} );
@@ -814,6 +817,12 @@ void TextDocument::notifyLineCountChanged( const size_t& lastCount, const size_t
}
}
void TextDocument::notifyLineChanged( const Int64& lineIndex ) {
for ( auto& client : mClients ) {
client->onDocumentLineChanged( lineIndex );
}
}
TextDocument::Client::~Client() {}
}}} // namespace EE::UI::Doc

View File

@@ -23,6 +23,7 @@ UICodeEditor::UICodeEditor() :
mCursorVisible( false ),
mMouseDown( false ),
mShowLineNumber( true ),
mLocked( false ),
mTabWidth( 4 ),
mLastColOffset( 0 ),
mMouseWheelScroll( 50 ),
@@ -95,10 +96,12 @@ void UICodeEditor::draw() {
Primitives primitives;
TextPosition cursor( mDoc.getSelection().start() );
primitives.setColor( mCurrentLineBackgroundColor );
primitives.drawRectangle(
Rectf( Vector2f( startScroll.x + mScroll.x, startScroll.y + cursor.line() * lineHeight ),
Sizef( mSize.getWidth(), lineHeight ) ) );
if ( !mLocked ) {
primitives.setColor( mCurrentLineBackgroundColor );
primitives.drawRectangle( Rectf(
Vector2f( startScroll.x + mScroll.x, startScroll.y + cursor.line() * lineHeight ),
Sizef( mSize.getWidth(), lineHeight ) ) );
}
if ( mDoc.hasSelection() ) {
primitives.setColor( mFontStyleConfig.getFontSelectionBackColor() );
@@ -109,7 +112,7 @@ void UICodeEditor::draw() {
int endLine = eemin<int>( lineRange.second, selection.end().line() );
for ( auto ln = startLine; ln <= endLine; ln++ ) {
const String& line = mDoc.line( ln );
const String& line = mDoc.line( ln ).getText();
Rectf selRect;
selRect.Top = startScroll.y + ln * lineHeight;
selRect.Bottom = selRect.Top + lineHeight;
@@ -137,21 +140,23 @@ void UICodeEditor::draw() {
for ( int i = lineRange.first; i <= lineRange.second; i++ ) {
Vector2f curPos( startScroll.x, startScroll.y + lineHeight * i );
auto& tokens = mHighlighter.getLine( i );
Text line( "", mFont, charSize );
line.setStyleConfig( mFontStyleConfig );
for ( auto& token : tokens ) {
Float textWidth = getTextWidth( token.text );
if ( curPos.x + textWidth >= mScreenPos.x &&
curPos.x <= mScreenPos.x + mSize.getWidth() ) {
Text line( "", mFont, charSize );
line.setStyleConfig( mFontStyleConfig );
line.setString( token.text );
line.setColor( mColorScheme.getColor( token.type ) );
line.draw( curPos.x, curPos.y );
} else if ( curPos.x > mScreenPos.x + mSize.getWidth() ) {
break;
}
curPos.x += textWidth;
}
}
if ( mCursorVisible ) {
if ( mCursorVisible && !mLocked ) {
Vector2f cursorPos( startScroll.x + getXOffsetCol( cursor ),
startScroll.y + cursor.line() * lineHeight );
@@ -188,6 +193,10 @@ void UICodeEditor::scheduledUpdate( const Time& ) {
mMouseDown = false;
getUISceneNode()->getWindow()->getInput()->captureMouse( false );
}
if ( mHighlighter.updateDirty( getVisibleLinesCount() ) ) {
invalidateDraw();
}
}
void UICodeEditor::reset() {
@@ -391,7 +400,7 @@ Uint32 UICodeEditor::onFocusLoss() {
}
Uint32 UICodeEditor::onTextInput( const TextInputEvent& event ) {
if ( NULL == mFont )
if ( mLocked || NULL == mFont )
return 1;
if ( !getUISceneNode()->getWindow()->getInput()->isControlPressed() ) {
@@ -404,6 +413,14 @@ Uint32 UICodeEditor::onKeyDown( const KeyEvent& event ) {
if ( NULL == mFont )
return 1;
// Allow copy selection on locked mode
if ( mLocked ) {
if ( event.getKeyCode() == KEY_C && ( event.getMod() & KEYMOD_CTRL ) ) {
getUISceneNode()->getWindow()->getClipboard()->setText( mDoc.getSelectedText() );
}
return 1;
}
switch ( event.getKeyCode() ) {
case KEY_BACKSPACE: {
if ( event.getMod() & KEYMOD_CTRL ) {
@@ -662,7 +679,7 @@ Uint32 UICodeEditor::onMouseUp( const Vector2i& position, const Uint32& flags )
}
Uint32 UICodeEditor::onMouseDoubleClick( const Vector2i&, const Uint32& flags ) {
if ( NULL == mFont )
if ( !mLocked || NULL == mFont )
return 1;
if ( flags & EE_BUTTON_LMASK ) {
@@ -672,7 +689,7 @@ Uint32 UICodeEditor::onMouseDoubleClick( const Vector2i&, const Uint32& flags )
}
Uint32 UICodeEditor::onMouseOver( const Vector2i& position, const Uint32& flags ) {
getUISceneNode()->setCursor( Cursor::IBeam );
getUISceneNode()->setCursor( !mLocked ? Cursor::IBeam : Cursor::Arrow );
return UIWidget::onMouseOver( position, flags );
}
@@ -728,6 +745,10 @@ void UICodeEditor::onDocumentLineCountChange( const size_t&, const size_t& ) {
updateScrollBar();
}
void UICodeEditor::onDocumentLineChanged( const Int64& lineIndex ) {
mHighlighter.invalidate( lineIndex );
}
std::pair<int, int> UICodeEditor::getVisibleLineRange() {
Float lineHeight = getLineHeight();
Float minLine = eemax( 0.f, eefloor( mScroll.y / lineHeight ) );
@@ -775,7 +796,7 @@ void UICodeEditor::setScrollY( const Float& val, bool emmitEvent ) {
}
Float UICodeEditor::getXOffsetCol( const TextPosition& position ) const {
const String& line = mDoc.line( position.line() );
const String& line = mDoc.line( position.line() ).getText();
Float glyphWidth = getGlyphWidth();
Float x = 0;
for ( auto i = 0; i < position.column(); i++ ) {
@@ -792,37 +813,42 @@ Float UICodeEditor::getTextWidth( const String& line ) const {
Float glyphWidth = getGlyphWidth();
size_t len = line.length();
Float x = 0;
for ( size_t i = 0; i < len; i++ ) {
if ( line[i] == '\t' ) {
x += glyphWidth * mTabWidth;
} else if ( line[i] != '\n' && line[i] != '\r' ) {
x += glyphWidth;
}
}
for ( size_t i = 0; i < len; i++ )
x += ( line[i] == '\t' ) ? glyphWidth * mTabWidth : glyphWidth;
return x;
}
Float UICodeEditor::getColXOffset( TextPosition position ) {
position = mDoc.sanitizePosition( position );
position.setLine( eeclamp<Int64>( position.line(), 0L, mDoc.linesCount() - 1 ) );
// This is different from sanitizePosition, sinze allows the last character.
position.setColumn( eeclamp<Int64>( position.column(), 0L,
eemax<Int64>( 0, mDoc.line( position.line() ).size() ) ) );
return getTextWidth( mDoc.line( position.line() ).substr( 0, position.column() ) );
}
const bool& UICodeEditor::isLocked() const {
return mLocked;
}
void UICodeEditor::setLocked( bool locked ) {
if ( mLocked != locked ) {
mLocked = locked;
invalidateDraw();
}
}
Int64 UICodeEditor::getColFromXOffset( Int64 lineNumber, const Float& offset ) const {
if ( offset <= 0 )
return 0;
TextPosition pos = mDoc.sanitizePosition( TextPosition( lineNumber, 0 ) );
const String& line = mDoc.line( pos.line() );
const String& line = mDoc.line( pos.line() ).getText();
size_t len = line.length();
Float glyphWidth = getGlyphWidth();
Float x = 0;
for ( size_t i = 0; i < line.size(); i++ ) {
if ( line[i] == '\t' ) {
x += glyphWidth * mTabWidth;
} else if ( line[i] != '\n' && line[i] != '\r' ) {
x += glyphWidth;
}
if ( x >= offset ) {
for ( size_t i = 0; i < len; i++ ) {
x += ( line[i] == '\t' ) ? glyphWidth * mTabWidth : glyphWidth;
if ( x >= offset )
return i;
}
}
return static_cast<Int64>( line.size() ) - 1;
}

1705
src/thirdparty/crc/CRC.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@
EE::Window::Window* win = NULL;
UISceneNode* uiSceneNode = NULL;
UICodeEditor* codeEditor = NULL;
Console* console = NULL;
std::string curFile = "untitled";
const std::string& windowTitle = "eepp - Code Editor";
bool docDirtyState = false;
@@ -47,41 +48,52 @@ void openFileDialog() {
}
void mainLoop() {
if ( codeEditor->isDirty() != docDirtyState ) {
docDirtyState = codeEditor->isDirty();
setAppTitle( docDirtyState ? curFile + "*" : curFile );
}
Input* input = win->getInput();
input->update();
if ( ( input->isControlPressed() && input->isKeyUp( KEY_O ) ) || input->isKeyUp( KEY_F2 ) ) {
openFileDialog();
}
if ( win->isActive() ) {
if ( codeEditor->isDirty() != docDirtyState ) {
docDirtyState = codeEditor->isDirty();
setAppTitle( docDirtyState ? curFile + "*" : curFile );
}
if ( input->isControlPressed() && input->isKeyUp( KEY_S ) ) {
codeEditor->save();
}
if ( ( input->isControlPressed() && input->isKeyUp( KEY_O ) ) ||
input->isKeyUp( KEY_F2 ) ) {
openFileDialog();
}
if ( input->isKeyUp( KEY_F6 ) ) {
uiSceneNode->setHighlightOver( !uiSceneNode->getHighlightOver() );
}
if ( input->isControlPressed() && input->isKeyUp( KEY_S ) ) {
codeEditor->save();
}
if ( input->isKeyUp( KEY_F7 ) ) {
uiSceneNode->setDrawBoxes( !uiSceneNode->getDrawBoxes() );
}
if ( input->isKeyUp( KEY_F6 ) ) {
uiSceneNode->setHighlightOver( !uiSceneNode->getHighlightOver() );
}
if ( input->isKeyUp( KEY_F8 ) ) {
uiSceneNode->setDrawDebugData( !uiSceneNode->getDrawDebugData() );
}
if ( input->isKeyUp( KEY_F7 ) ) {
uiSceneNode->setDrawBoxes( !uiSceneNode->getDrawBoxes() );
}
if ( input->isKeyUp( KEY_ESCAPE ) && NULL == MsgBox && onCloseRequestCallback( win ) ) {
win->close();
}
if ( input->isKeyUp( KEY_F8 ) ) {
uiSceneNode->setDrawDebugData( !uiSceneNode->getDrawDebugData() );
}
if ( input->isAltPressed() && input->isKeyUp( KEY_RETURN ) ) {
win->toggleFullscreen();
if ( input->isKeyUp( KEY_ESCAPE ) && NULL == MsgBox && onCloseRequestCallback( win ) ) {
win->close();
}
if ( input->isAltPressed() && input->isKeyUp( KEY_RETURN ) ) {
win->toggleFullscreen();
}
if ( input->isKeyUp( KEY_F3 ) ) {
console->toggle();
}
if ( input->isControlPressed() && input->isKeyUp( KEY_L ) ) {
codeEditor->setLocked( !codeEditor->isLocked() );
}
}
SceneManager::instance()->update();
@@ -89,9 +101,10 @@ void mainLoop() {
if ( SceneManager::instance()->getUISceneNode()->invalidated() ) {
win->clear();
SceneManager::instance()->draw();
console->draw();
win->display();
} else {
Sys::sleep( Milliseconds( win->isVisible() ? 1 : 8 ) );
Sys::sleep( Milliseconds( win->isVisible() ? 1 : 16 ) );
}
}
@@ -143,7 +156,7 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
uiSceneNode->getUIThemeManager()->setDefaultFont(
FontTrueType::New( "NotoSans-Regular", "assets/fonts/NotoSans-Regular.ttf" ) );
FontTrueType::New( "monospace", "assets/fonts/DejaVuSansMono.ttf" );
Font* fontMono = FontTrueType::New( "monospace", "assets/fonts/DejaVuSansMono.ttf" );
SceneManager::instance()->add( uiSceneNode );
@@ -171,9 +184,13 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
loadFileFromPath( file.Get() );
}
console = eeNew( Console, ( fontMono, true, true, 1024 * 1000, 0, win ) );
win->runMainLoop( &mainLoop );
}
eeSAFE_DELETE( console );
Engine::destroySingleton();
MemoryManager::showResults();