mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-18 06:55:48 +03:00
More WIP on the code editor.
This commit is contained in:
@@ -12,6 +12,7 @@ class EE_API Event {
|
||||
enum EventType {
|
||||
KeyDown = 0,
|
||||
KeyUp,
|
||||
TextInput,
|
||||
MouseMove,
|
||||
MouseDown,
|
||||
MouseClick,
|
||||
|
||||
@@ -46,9 +46,11 @@ class EE_API EventDispatcher {
|
||||
|
||||
void sendMsg( Node* Ctrl, const Uint32& Msg, const Uint32& Flags = 0 );
|
||||
|
||||
void sendKeyUp( const Uint32& KeyCode, const Uint16& Char, const Uint32& Mod );
|
||||
void sendTextInput( const Uint32& textChar, const Uint32& timestamp );
|
||||
|
||||
void sendKeyDown( const Uint32& KeyCode, const Uint16& Char, const Uint32& Mod );
|
||||
void sendKeyUp( const Uint32& KeyCode, const Uint32& Char, const Uint32& Mod );
|
||||
|
||||
void sendKeyDown( const Uint32& KeyCode, const Uint32& Char, const Uint32& Mod );
|
||||
|
||||
void sendMouseClick( Node* ToCtrl, const Vector2i& Pos, const Uint32 Flags );
|
||||
|
||||
@@ -98,7 +100,7 @@ class EE_API EventDispatcher {
|
||||
Node* mNodeDragging;
|
||||
Time mElapsed;
|
||||
|
||||
virtual void inputCallback( InputEvent* Event );
|
||||
virtual void inputCallback( InputEvent* event );
|
||||
};
|
||||
|
||||
}} // namespace EE::Scene
|
||||
|
||||
@@ -1,29 +1,46 @@
|
||||
#ifndef EE_SCENEEVENTKEY_HPP
|
||||
#define EE_SCENEEVENTKEY_HPP
|
||||
|
||||
#include <eepp/core/string.hpp>
|
||||
#include <eepp/scene/event.hpp>
|
||||
|
||||
namespace EE { namespace Scene {
|
||||
|
||||
class EE_API KeyEvent : public Event {
|
||||
public:
|
||||
KeyEvent( Node* node, const Uint32& EventNum, const Uint32& getKeyCode, const Uint16& getChar,
|
||||
const Uint32& getMod );
|
||||
KeyEvent( Node* node, const Uint32& eventNum, const Uint32& keyCode, const Uint32& chr,
|
||||
const Uint32& mod );
|
||||
|
||||
~KeyEvent();
|
||||
|
||||
const Uint32& getKeyCode() const;
|
||||
|
||||
const Uint16& getChar() const;
|
||||
const Uint32& getChar() const;
|
||||
|
||||
const Uint32& getMod() const;
|
||||
|
||||
protected:
|
||||
Uint32 mKeyCode;
|
||||
Uint16 mChar;
|
||||
Uint32 mChar;
|
||||
Uint32 mMod;
|
||||
};
|
||||
|
||||
class EE_API TextInputEvent : public Event {
|
||||
public:
|
||||
TextInputEvent( Node* node, const Uint32& eventNum, const Uint32& chr,
|
||||
const Uint32& timestamp );
|
||||
|
||||
const Uint32& getChar() const;
|
||||
|
||||
const Uint32& getTimestamp() const;
|
||||
|
||||
String getText() const;
|
||||
|
||||
protected:
|
||||
Uint32 mChar;
|
||||
Uint32 mTimestamp;
|
||||
};
|
||||
|
||||
}} // namespace EE::Scene
|
||||
|
||||
#endif
|
||||
|
||||
@@ -405,6 +405,8 @@ class EE_API Node : public Transformable {
|
||||
|
||||
virtual Uint32 onMessage( const NodeMessage* Msg );
|
||||
|
||||
virtual Uint32 onTextInput( const TextInputEvent& Event );
|
||||
|
||||
virtual Uint32 onKeyDown( const KeyEvent& Event );
|
||||
|
||||
virtual Uint32 onKeyUp( const KeyEvent& Event );
|
||||
|
||||
@@ -19,6 +19,8 @@ class EE_API TextDocument {
|
||||
virtual void onDocumentSelectionChange( const TextRange& ) = 0;
|
||||
};
|
||||
|
||||
enum IndentType { IndentSpaces, IndentTabs };
|
||||
|
||||
static bool isNonWord( String::StringBaseType ch );
|
||||
|
||||
TextDocument();
|
||||
@@ -102,6 +104,8 @@ class EE_API TextDocument {
|
||||
|
||||
void moveTo( TextPosition offset );
|
||||
|
||||
void moveTo( int columnOffset );
|
||||
|
||||
void textInput( const String& text );
|
||||
|
||||
void registerClient( Client& client );
|
||||
@@ -120,12 +124,28 @@ class EE_API TextDocument {
|
||||
|
||||
void moveToNextPage( Int64 pageSize );
|
||||
|
||||
void deleteToPreviousChar();
|
||||
|
||||
void deleteToNextChar();
|
||||
|
||||
void newLine();
|
||||
|
||||
void indent();
|
||||
|
||||
void unindent();
|
||||
|
||||
String getIndentString();
|
||||
|
||||
const Uint32& getTabWidth() const;
|
||||
|
||||
void setTabWidth( const Uint32& tabWidth );
|
||||
|
||||
TextPosition sanitizePosition( const TextPosition& position ) const;
|
||||
|
||||
const IndentType& getIndentType() const;
|
||||
|
||||
void setIndentType( const IndentType& indentType );
|
||||
|
||||
protected:
|
||||
std::string mFilename;
|
||||
std::vector<String> mLines;
|
||||
@@ -133,12 +153,17 @@ class EE_API TextDocument {
|
||||
std::unordered_set<Client*> mClients;
|
||||
bool mIsCLRF;
|
||||
Uint32 mTabWidth{4};
|
||||
IndentType mIndentType{IndentTabs};
|
||||
|
||||
void notifyTextChanged();
|
||||
|
||||
void notifyCursorChanged();
|
||||
|
||||
void notifySelectionChanged();
|
||||
|
||||
void insertAtStartOfSelectedLines( String text, bool skipEmpty );
|
||||
|
||||
void removeFromStartOfSelectedLines( String text, bool skipEmpty );
|
||||
};
|
||||
|
||||
}}} // namespace EE::UI::Doc
|
||||
|
||||
@@ -43,6 +43,10 @@ class EE_API UICodeEdit : public UIWidget, public TextDocument::Client {
|
||||
const Uint32& getTabWidth() const;
|
||||
void setTabWidth( const Uint32& tabWidth );
|
||||
|
||||
const Float& getMouseWheelScroll() const;
|
||||
|
||||
void setMouseWheelScroll( const Float& mouseWheelScroll );
|
||||
|
||||
protected:
|
||||
Font* mFont;
|
||||
UIFontStyleConfig mFontStyleConfig;
|
||||
@@ -54,13 +58,18 @@ class EE_API UICodeEdit : public UIWidget, public TextDocument::Client {
|
||||
Uint32 mTabWidth;
|
||||
Int64 mLastColOffset;
|
||||
Vector2f mScroll;
|
||||
Float mMouseWheelScroll;
|
||||
|
||||
void invalidateEditor();
|
||||
|
||||
virtual Uint32 onTextInput( const TextInputEvent& event );
|
||||
|
||||
virtual Uint32 onKeyDown( const KeyEvent& Event );
|
||||
|
||||
virtual Uint32 onMouseDown( const Vector2i& position, const Uint32& flags );
|
||||
|
||||
virtual Uint32 onMouseUp( const Vector2i& position, const Uint32& flags );
|
||||
|
||||
virtual void onSizeChange();
|
||||
|
||||
virtual void onPaddingChange();
|
||||
@@ -90,6 +99,10 @@ class EE_API UICodeEdit : public UIWidget, public TextDocument::Client {
|
||||
void updateLastColumnOffset();
|
||||
|
||||
TextPosition resolveScreenPosition( const Vector2f& position ) const;
|
||||
|
||||
Vector2f getViewPortLineCount() const;
|
||||
|
||||
Sizef getMaxScroll() const;
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -41,7 +41,7 @@ class InputEvent {
|
||||
struct KeySym {
|
||||
Uint32 sym; /** virtual keysym */
|
||||
Uint32 mod; /** current key modifiers */
|
||||
Uint16 unicode; /** translated character */
|
||||
Uint32 unicode; /** translated character */
|
||||
};
|
||||
|
||||
/** Application visibility event structure */
|
||||
@@ -93,7 +93,7 @@ class InputEvent {
|
||||
Uint32 timestamp;
|
||||
Uint32 text;
|
||||
|
||||
String Text() { return String( text ); }
|
||||
String getText() { return String( text ); }
|
||||
};
|
||||
|
||||
/** Joystick axis motion event structure */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.12.0, 2020-05-20T05:57:57. -->
|
||||
<!-- Written by QtCreator 4.12.0, 2020-05-20T19:32:27. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
||||
@@ -33,21 +33,23 @@ EventDispatcher::~EventDispatcher() {
|
||||
}
|
||||
}
|
||||
|
||||
void EventDispatcher::inputCallback( InputEvent* Event ) {
|
||||
switch ( Event->Type ) {
|
||||
void EventDispatcher::inputCallback( InputEvent* event ) {
|
||||
switch ( event->Type ) {
|
||||
case InputEvent::Window: {
|
||||
if ( Event->window.type == InputEvent::WindowKeyboardFocusGain ) {
|
||||
if ( event->window.type == InputEvent::WindowKeyboardFocusGain ) {
|
||||
mMousePosi = mInput->queryMousePos();
|
||||
mMousePos = mMousePosi.asFloat();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InputEvent::KeyUp:
|
||||
sendKeyUp( Event->key.keysym.sym, Event->key.keysym.unicode, Event->key.keysym.mod );
|
||||
sendKeyUp( event->key.keysym.sym, event->key.keysym.unicode, event->key.keysym.mod );
|
||||
break;
|
||||
case InputEvent::KeyDown:
|
||||
sendKeyDown( Event->key.keysym.sym, Event->key.keysym.unicode, Event->key.keysym.mod );
|
||||
sendKeyDown( event->key.keysym.sym, event->key.keysym.unicode, event->key.keysym.mod );
|
||||
break;
|
||||
case InputEvent::TextInput:
|
||||
sendTextInput( event->text.text, event->text.timestamp );
|
||||
case InputEvent::SysWM:
|
||||
case InputEvent::VideoResize:
|
||||
case InputEvent::VideoExpose: {
|
||||
@@ -151,7 +153,20 @@ Input* EventDispatcher::getInput() const {
|
||||
return mInput;
|
||||
}
|
||||
|
||||
void EventDispatcher::sendKeyUp( const Uint32& KeyCode, const Uint16& Char, const Uint32& Mod ) {
|
||||
void EventDispatcher::sendTextInput( const Uint32& textChar, const Uint32& timestamp ) {
|
||||
TextInputEvent textInputEvent =
|
||||
TextInputEvent( mFocusControl, Event::TextInput, textChar, timestamp );
|
||||
Node* CtrlLoop = mFocusControl;
|
||||
|
||||
while ( NULL != CtrlLoop ) {
|
||||
if ( CtrlLoop->isEnabled() && CtrlLoop->onTextInput( textInputEvent ) )
|
||||
break;
|
||||
|
||||
CtrlLoop = CtrlLoop->getParent();
|
||||
}
|
||||
}
|
||||
|
||||
void EventDispatcher::sendKeyUp( const Uint32& KeyCode, const Uint32& Char, const Uint32& Mod ) {
|
||||
KeyEvent keyEvent = KeyEvent( mFocusControl, Event::KeyUp, KeyCode, Char, Mod );
|
||||
Node* CtrlLoop = mFocusControl;
|
||||
|
||||
@@ -163,7 +178,7 @@ void EventDispatcher::sendKeyUp( const Uint32& KeyCode, const Uint16& Char, cons
|
||||
}
|
||||
}
|
||||
|
||||
void EventDispatcher::sendKeyDown( const Uint32& KeyCode, const Uint16& Char, const Uint32& Mod ) {
|
||||
void EventDispatcher::sendKeyDown( const Uint32& KeyCode, const Uint32& Char, const Uint32& Mod ) {
|
||||
KeyEvent keyEvent = KeyEvent( mFocusControl, Event::KeyDown, KeyCode, Char, Mod );
|
||||
Node* CtrlLoop = mFocusControl;
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
namespace EE { namespace Scene {
|
||||
|
||||
KeyEvent::KeyEvent( Node* node, const Uint32& EventNum, const Uint32& KeyCode, const Uint16& Char,
|
||||
const Uint32& Mod ) :
|
||||
Event( node, EventNum ), mKeyCode( KeyCode ), mChar( Char ), mMod( Mod ) {}
|
||||
KeyEvent::KeyEvent( Node* node, const Uint32& eventNum, const Uint32& keyCode, const Uint32& chr,
|
||||
const Uint32& mod ) :
|
||||
Event( node, eventNum ), mKeyCode( keyCode ), mChar( chr ), mMod( mod ) {}
|
||||
|
||||
KeyEvent::~KeyEvent() {}
|
||||
|
||||
@@ -13,7 +13,7 @@ const Uint32& KeyEvent::getKeyCode() const {
|
||||
return mKeyCode;
|
||||
}
|
||||
|
||||
const Uint16& KeyEvent::getChar() const {
|
||||
const Uint32& KeyEvent::getChar() const {
|
||||
return mChar;
|
||||
}
|
||||
|
||||
@@ -21,4 +21,20 @@ const Uint32& KeyEvent::getMod() const {
|
||||
return mMod;
|
||||
}
|
||||
|
||||
TextInputEvent::TextInputEvent( Node* node, const Uint32& eventNum, const Uint32& chr,
|
||||
const Uint32& timestamp ) :
|
||||
Event( node, eventNum ), mChar( chr ), mTimestamp( timestamp ) {}
|
||||
|
||||
const Uint32& TextInputEvent::getChar() const {
|
||||
return mChar;
|
||||
}
|
||||
|
||||
const Uint32& TextInputEvent::getTimestamp() const {
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
String TextInputEvent::getText() const {
|
||||
return String( mChar );
|
||||
}
|
||||
|
||||
}} // namespace EE::Scene
|
||||
|
||||
@@ -307,6 +307,11 @@ void Node::sendCommonEvent( const Uint32& event ) {
|
||||
sendEvent( &CommonEvent );
|
||||
}
|
||||
|
||||
Uint32 Node::onTextInput( const TextInputEvent& event ) {
|
||||
sendEvent( &event );
|
||||
return 0;
|
||||
}
|
||||
|
||||
Uint32 Node::onKeyDown( const KeyEvent& Event ) {
|
||||
sendEvent( &Event );
|
||||
return 0;
|
||||
|
||||
@@ -145,39 +145,40 @@ TextPosition TextDocument::insert( const TextPosition& position, const String& t
|
||||
|
||||
TextPosition TextDocument::insert( TextPosition position, const String::StringBaseType& ch ) {
|
||||
position = sanitizePosition( position );
|
||||
size_t tabWidth = mTabWidth;
|
||||
bool atHead = position.column() == 0;
|
||||
bool atTail = position.column() == (Int64)line( position.line() ).length();
|
||||
bool atTail = position.column() == (Int64)line( position.line() ).length() - 1;
|
||||
if ( ch == '\n' ) {
|
||||
if ( atTail || atHead ) {
|
||||
String new_line_contents;
|
||||
String newLineContents( "\n" );
|
||||
size_t row = position.line();
|
||||
String line_content;
|
||||
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 ),
|
||||
new_line_contents );
|
||||
return {position.line() + 1, (Int64)line( position.line() + 1 ).length()};
|
||||
mLines.insert( mLines.begin() + position.line() + ( atTail ? 1 : 0 ), newLineContents );
|
||||
notifyTextChanged();
|
||||
if ( atTail )
|
||||
return {position.line() + 1, (Int64)line( position.line() + 1 ).length()};
|
||||
return {position.line() + 1, 0};
|
||||
}
|
||||
String newLine;
|
||||
newLine +=
|
||||
String newLine =
|
||||
line( position.line() )
|
||||
.substr( position.column(), line( position.line() ).length() - position.column() );
|
||||
|
||||
String lineContent( newLine );
|
||||
line( position.line() ).substr( 0, position.column() );
|
||||
line( position.line() ) = line( position.line() ).substr( 0, position.column() );
|
||||
mLines.insert( mLines.begin() + position.line() + 1, std::move( newLine ) );
|
||||
notifyTextChanged();
|
||||
return {position.line() + 1, 0};
|
||||
} else if ( ch == '\t' ) {
|
||||
Int64 nextSoftTabStop = ( ( position.column() + tabWidth ) / tabWidth ) * tabWidth;
|
||||
size_t spaces_to_insert = nextSoftTabStop - position.column();
|
||||
for ( size_t i = 0; i < spaces_to_insert; ++i ) {
|
||||
line( position.line() )
|
||||
.insert( line( position.line() ).begin() + position.column(), ' ' );
|
||||
}
|
||||
return {position.line(), nextSoftTabStop};
|
||||
}
|
||||
} /* else if ( ch == '\t' ) {
|
||||
Int64 nextSoftTabStop =
|
||||
( ( position.column() + tabWidth ) / getTabWidth() ) * getTabWidth();
|
||||
size_t spacesToInsert = nextSoftTabStop - position.column();
|
||||
for ( size_t i = 0; i < spacesToInsert; ++i ) {
|
||||
line( position.line() )
|
||||
.insert( line( position.line() ).begin() + position.column(), ' ' );
|
||||
}
|
||||
return {position.line(), nextSoftTabStop};
|
||||
}*/
|
||||
line( position.line() ).insert( line( position.line() ).begin() + position.column(), ch );
|
||||
notifyTextChanged();
|
||||
return {position.line(), position.column() + 1};
|
||||
}
|
||||
|
||||
@@ -202,32 +203,33 @@ void TextDocument::remove( TextRange range ) {
|
||||
if ( range.start().line() == range.end().line() ) {
|
||||
// Delete within same line.
|
||||
auto& line = this->line( range.start().line() );
|
||||
bool whole_line_is_selected =
|
||||
bool wholeLineIsSelected =
|
||||
range.start().column() == 0 && range.end().column() == (Int64)line.length();
|
||||
|
||||
if ( whole_line_is_selected ) {
|
||||
if ( wholeLineIsSelected ) {
|
||||
line.clear();
|
||||
} else {
|
||||
auto before_selection = line.substr( 0, range.start().column() );
|
||||
auto after_selection =
|
||||
auto beforeSelection = line.substr( 0, range.start().column() );
|
||||
auto afterSelection =
|
||||
line.substr( range.end().column(), line.length() - range.end().column() );
|
||||
line.assign( before_selection + after_selection );
|
||||
line.assign( beforeSelection + afterSelection );
|
||||
}
|
||||
} else {
|
||||
// Delete across a newline, merging lines.
|
||||
eeASSERT( range.start().line() == range.end().line() - 1 );
|
||||
auto& first_line = line( range.start().line() );
|
||||
auto& second_line = line( range.end().line() );
|
||||
auto before_selection = first_line.substr( 0, range.start().column() );
|
||||
auto after_selection =
|
||||
second_line.substr( range.end().column(), second_line.length() - range.end().column() );
|
||||
first_line.assign( before_selection + after_selection );
|
||||
auto& firstLine = line( range.start().line() );
|
||||
auto& secondLine = line( range.end().line() );
|
||||
auto beforeSelection = firstLine.substr( 0, range.start().column() );
|
||||
auto afterSelection =
|
||||
secondLine.substr( range.end().column(), secondLine.length() - range.end().column() );
|
||||
firstLine.assign( beforeSelection + afterSelection );
|
||||
mLines.erase( mLines.begin() + range.end().line() );
|
||||
}
|
||||
|
||||
if ( lines().empty() ) {
|
||||
mLines.emplace_back( String() );
|
||||
}
|
||||
notifyTextChanged();
|
||||
}
|
||||
|
||||
TextPosition TextDocument::positionOffset( TextPosition position, int columnOffset ) const {
|
||||
@@ -235,11 +237,11 @@ TextPosition TextDocument::positionOffset( TextPosition position, int columnOffs
|
||||
position.setColumn( position.column() + columnOffset );
|
||||
while ( position.line() > 0 && position.column() < 0 ) {
|
||||
position.setLine( position.line() - 1 );
|
||||
position.setColumn( position.column() + mLines[position.line()].size() );
|
||||
position.setColumn( eemax<Int64>( 0, position.column() + mLines[position.line()].size() ) );
|
||||
}
|
||||
while ( position.line() < (Int64)mLines.size() &&
|
||||
position.column() > (Int64)mLines[position.line()].size() - 1 ) {
|
||||
position.setColumn( position.column() - mLines[position.line()].size() );
|
||||
position.column() > (Int64)eemax<Int64>( 0, mLines[position.line()].size() - 1 ) ) {
|
||||
position.setColumn( position.column() - mLines[position.line()].size() - 1 );
|
||||
position.setLine( position.line() + 1 );
|
||||
}
|
||||
return sanitizePosition( position );
|
||||
@@ -377,13 +379,15 @@ void TextDocument::moveTo( TextPosition offset ) {
|
||||
setSelection( getSelection().start() + offset );
|
||||
}
|
||||
|
||||
void TextDocument::moveTo( int columnOffset ) {
|
||||
setSelection( positionOffset( getSelection().start(), columnOffset ) );
|
||||
}
|
||||
|
||||
void TextDocument::textInput( const String& text ) {
|
||||
if ( hasSelection() ) {
|
||||
deleteTo( 0 );
|
||||
}
|
||||
TextPosition start = getSelection().start();
|
||||
insert( start, text );
|
||||
moveTo( TextPosition( 0, text.size() ) );
|
||||
setSelection( insert( getSelection().start(), text ) );
|
||||
}
|
||||
|
||||
void TextDocument::registerClient( TextDocument::Client& client ) {
|
||||
@@ -444,6 +448,84 @@ void TextDocument::moveToNextPage( Int64 pageSize ) {
|
||||
setSelection( pos );
|
||||
}
|
||||
|
||||
void TextDocument::deleteToPreviousChar() {
|
||||
deleteTo( -1 );
|
||||
}
|
||||
|
||||
void TextDocument::deleteToNextChar() {
|
||||
deleteTo( 1 );
|
||||
}
|
||||
|
||||
void TextDocument::newLine() {
|
||||
String input( "\n" );
|
||||
TextPosition start = getSelection().start();
|
||||
if ( start.line() >= 0 && start.line() < (Int64)mLines.size() ) {
|
||||
String& ln = line( start.line() );
|
||||
size_t to = eemin<size_t>( ln.size(), start.column() );
|
||||
int indent = 0;
|
||||
for ( size_t i = 0; i < to; i++ ) {
|
||||
if ( '\t' == ln[i] || ' ' == ln[i] ) {
|
||||
indent++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( indent ) {
|
||||
input.append( ln.substr( 0, indent ) );
|
||||
}
|
||||
}
|
||||
textInput( input );
|
||||
}
|
||||
|
||||
void TextDocument::insertAtStartOfSelectedLines( 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 );
|
||||
if ( !skipEmpty || line.length() != 1 ) {
|
||||
insert( {i, 0}, text );
|
||||
}
|
||||
}
|
||||
setSelection( TextPosition( range.start().line(), range.start().column() + text.size() ),
|
||||
TextPosition( range.end().line(), range.end().column() + text.size() ), swap );
|
||||
}
|
||||
|
||||
void TextDocument::removeFromStartOfSelectedLines( 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 );
|
||||
if ( !skipEmpty || line.length() != 1 ) {
|
||||
if ( line.substr( 0, text.length() ) == text ) {
|
||||
remove( {{i, 0}, {i, static_cast<Int64>( text.length() )}} );
|
||||
}
|
||||
}
|
||||
}
|
||||
setSelection( TextPosition( range.start().line(), range.start().column() - text.size() ),
|
||||
TextPosition( range.end().line(), range.end().column() - text.size() ), swap );
|
||||
}
|
||||
|
||||
void TextDocument::indent() {
|
||||
if ( hasSelection() ) {
|
||||
insertAtStartOfSelectedLines( getIndentString(), false );
|
||||
} else {
|
||||
textInput( getIndentString() );
|
||||
}
|
||||
}
|
||||
|
||||
void TextDocument::unindent() {
|
||||
removeFromStartOfSelectedLines( getIndentString(), false );
|
||||
}
|
||||
|
||||
String TextDocument::getIndentString() {
|
||||
if ( IndentSpaces == mIndentType ) {
|
||||
return String( std::string( mTabWidth, ' ' ) );
|
||||
}
|
||||
return String( "\t" );
|
||||
}
|
||||
|
||||
const Uint32& TextDocument::getTabWidth() const {
|
||||
return mTabWidth;
|
||||
}
|
||||
@@ -473,10 +555,19 @@ void TextDocument::print() const {
|
||||
|
||||
TextPosition TextDocument::sanitizePosition( const TextPosition& position ) const {
|
||||
Int64 line = eeclamp<Int64>( position.line(), 0UL, mLines.size() - 1 );
|
||||
Int64 col = eeclamp<Int64>( position.column(), 0UL, mLines[line].size() - 1 );
|
||||
Int64 col =
|
||||
eeclamp<Int64>( position.column(), 0UL, eemax<Int64>( 0, mLines[line].size() - 1 ) );
|
||||
return {line, col};
|
||||
}
|
||||
|
||||
const TextDocument::IndentType& TextDocument::getIndentType() const {
|
||||
return mIndentType;
|
||||
}
|
||||
|
||||
void TextDocument::setIndentType( const IndentType& indentType ) {
|
||||
mIndentType = indentType;
|
||||
}
|
||||
|
||||
void TextDocument::notifyTextChanged() {
|
||||
for ( auto& client : mClients ) {
|
||||
client->onDocumentTextChanged();
|
||||
|
||||
@@ -19,7 +19,8 @@ UICodeEdit::UICodeEdit() :
|
||||
mDirtyEditor( false ),
|
||||
mCursorVisible( false ),
|
||||
mTabWidth( 4 ),
|
||||
mLastColOffset( 0 ) {
|
||||
mLastColOffset( 0 ),
|
||||
mMouseWheelScroll( 50 ) {
|
||||
clipEnable();
|
||||
if ( NULL == mFont ) {
|
||||
mFont = FontTrueType::New( "monospace", "assets/fonts/DejaVuSansMono.ttf" );
|
||||
@@ -124,12 +125,40 @@ void UICodeEdit::setTabWidth( const Uint32& tabWidth ) {
|
||||
}
|
||||
}
|
||||
|
||||
const Float& UICodeEdit::getMouseWheelScroll() const {
|
||||
return mMouseWheelScroll;
|
||||
}
|
||||
|
||||
void UICodeEdit::setMouseWheelScroll( const Float& mouseWheelScroll ) {
|
||||
mMouseWheelScroll = mouseWheelScroll;
|
||||
}
|
||||
|
||||
void UICodeEdit::invalidateEditor() {
|
||||
mDirtyEditor = true;
|
||||
}
|
||||
|
||||
Uint32 UICodeEdit::onTextInput( const TextInputEvent& event ) {
|
||||
mDoc.textInput( event.getText() );
|
||||
return 1;
|
||||
}
|
||||
|
||||
Uint32 UICodeEdit::onKeyDown( const KeyEvent& event ) {
|
||||
switch ( event.getKeyCode() ) {
|
||||
case KEY_BACKSPACE: {
|
||||
mDoc.deleteToPreviousChar();
|
||||
updateLastColumnOffset();
|
||||
break;
|
||||
}
|
||||
case KEY_DELETE: {
|
||||
mDoc.deleteToNextChar();
|
||||
break;
|
||||
}
|
||||
case KEY_KP_ENTER:
|
||||
case KEY_RETURN: {
|
||||
mDoc.newLine();
|
||||
updateLastColumnOffset();
|
||||
break;
|
||||
}
|
||||
case KEY_UP: {
|
||||
mDoc.moveToPreviousLine( mLastColOffset );
|
||||
break;
|
||||
@@ -168,6 +197,16 @@ Uint32 UICodeEdit::onKeyDown( const KeyEvent& event ) {
|
||||
updateLastColumnOffset();
|
||||
break;
|
||||
}
|
||||
case KEY_TAB: {
|
||||
if ( event.getMod() & KEYMOD_LSHIFT ) {
|
||||
mDoc.unindent();
|
||||
updateLastColumnOffset();
|
||||
} else if ( !event.getMod() ) {
|
||||
mDoc.indent();
|
||||
updateLastColumnOffset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -187,6 +226,19 @@ TextPosition UICodeEdit::resolveScreenPosition( const Vector2f& position ) const
|
||||
return TextPosition( line, getColFromXOffset( line, localPos.x ) );
|
||||
}
|
||||
|
||||
Vector2f UICodeEdit::getViewPortLineCount() const {
|
||||
return Vector2f( eefloor( mSize.getWidth() / getGlyphWidth() ),
|
||||
eefloor( mSize.getHeight() / getLineHeight() ) );
|
||||
}
|
||||
|
||||
Sizef UICodeEdit::getMaxScroll() const {
|
||||
Vector2f vplc( getViewPortLineCount() );
|
||||
return Sizef( 0 /*TODO: Implement*/,
|
||||
vplc.y > mDoc.lineCount() - 1
|
||||
? 0.f
|
||||
: ( mDoc.lineCount() - getViewPortLineCount().y ) * getLineHeight() );
|
||||
}
|
||||
|
||||
Uint32 UICodeEdit::onMouseDown( const Vector2i& position, const Uint32& flags ) {
|
||||
if ( flags & EE_BUTTON_LMASK ) {
|
||||
mDoc.setSelection( resolveScreenPosition( position.asFloat() ) );
|
||||
@@ -194,8 +246,22 @@ Uint32 UICodeEdit::onMouseDown( const Vector2i& position, const Uint32& flags )
|
||||
return UIWidget::onMouseDown( position, flags );
|
||||
}
|
||||
|
||||
Uint32 UICodeEdit::onMouseUp( const Vector2i& position, const Uint32& flags ) {
|
||||
if ( flags & EE_BUTTON_WDMASK ) {
|
||||
mScroll.y += PixelDensity::dpToPx( mMouseWheelScroll );
|
||||
mScroll.y = eemin( mScroll.y, getMaxScroll().y );
|
||||
invalidateDraw();
|
||||
} else if ( flags & EE_BUTTON_WUMASK ) {
|
||||
mScroll.y -= PixelDensity::dpToPx( mMouseWheelScroll );
|
||||
mScroll.y = eemax( mScroll.y, 0.f );
|
||||
invalidateDraw();
|
||||
}
|
||||
return UIWidget::onMouseUp( position, flags );
|
||||
}
|
||||
|
||||
void UICodeEdit::onSizeChange() {
|
||||
UIWidget::onSizeChange();
|
||||
mScroll = {0, 0};
|
||||
invalidateEditor();
|
||||
}
|
||||
|
||||
@@ -206,6 +272,7 @@ void UICodeEdit::onPaddingChange() {
|
||||
|
||||
void UICodeEdit::updateEditor() {
|
||||
scrollToMakeVisible( mDoc.getSelection().start() );
|
||||
mDirtyEditor = false;
|
||||
}
|
||||
|
||||
void UICodeEdit::onDocumentTextChanged() {
|
||||
|
||||
@@ -28,14 +28,14 @@ void mainLoop() {
|
||||
}
|
||||
|
||||
EE_MAIN_FUNC int main( int, char** ) {
|
||||
Doc::TextDocument doc;
|
||||
/*Doc::TextDocument doc;
|
||||
doc.loadFromPath( "/home/downloads/textposition.hpp" );
|
||||
doc.remove( TextRange( TextPosition( 0, 0 ), TextPosition( 1, 40 ) ) );
|
||||
doc.insert( TextPosition( 0, 0 ),
|
||||
String( "#ifndef EE_UI_DOC_TEXPOS\n#define EE_UI_DOC_TEXPOS" ) );
|
||||
doc.remove( TextRange( TextPosition( 31, 2 ), TextPosition( 33, 15 ) ) );
|
||||
doc.insert( TextPosition( 31, 2 ), String( "hexNumber" ) );
|
||||
doc.print();
|
||||
doc.print();*/
|
||||
// return EXIT_SUCCESS;
|
||||
win = Engine::instance()->createWindow( WindowSettings( 640, 480, "eepp - UI Hello World" ),
|
||||
ContextSettings( true ) );
|
||||
|
||||
Reference in New Issue
Block a user