From 62c83cb9b2dc30d43a02fc927aa0c7f443fb1f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 22 Dec 2013 11:54:13 -0300 Subject: [PATCH] More work on text selection. --- include/eepp/window/cinputtextbuffer.hpp | 15 +- .../gaming/mapeditor/clayerproperties.cpp | 2 +- src/eepp/gaming/mapeditor/cmapproperties.cpp | 2 +- .../gaming/mapeditor/cobjectproperties.cpp | 2 +- src/eepp/ui/cuitextbox.cpp | 7 +- src/eepp/ui/cuitextinput.cpp | 1 + src/eepp/window/cinputtextbuffer.cpp | 157 +++++++++++++----- src/test/eetest.cpp | 36 ++-- 8 files changed, 163 insertions(+), 59 deletions(-) diff --git a/include/eepp/window/cinputtextbuffer.hpp b/include/eepp/window/cinputtextbuffer.hpp index b83aebc53..b4ffcb766 100755 --- a/include/eepp/window/cinputtextbuffer.hpp +++ b/include/eepp/window/cinputtextbuffer.hpp @@ -15,7 +15,8 @@ enum INPUT_TEXTBUFFER_FLAGS { INPUT_TB_CHANGE_SINCE_LAST_UPDATE = 4, INPUT_TB_FREE_EDITING = 5, INPUT_TB_PROMPT_AUTO_POS = 6, - INPUT_TB_SUPPORT_COPY_PASTE = 7 + INPUT_TB_SUPPORT_COPY_PASTE = 7, + INPUT_TB_TEXT_SELECTION_ENABLED = 8 }; #define INPUT_LENGHT_MAX 0xFFFFFFFF @@ -64,6 +65,12 @@ class EE_API cInputTextBuffer { /** @return If is only allowing numbers, it allow floating point numbers? */ bool AllowDotsInNumbers(); + /** @return If text selection feature is enabled */ + bool TextSelectionEnabled(); + + /** Enable text selection */ + void TextSelectionEnabled( const bool& enabled ); + /** Start the input buffer */ void Start(); @@ -149,6 +156,8 @@ class EE_API cInputTextBuffer { void PromptToRightFirstNoChar(); + void EraseToPrevNoChar(); + void EraseToNextNoChar(); bool IsIgnoredChar( const Uint32& c ); @@ -158,6 +167,10 @@ class EE_API cInputTextBuffer { void TryAddChar( const Uint32& c ); void ShiftSelection( const eeInt& lastPromtpPos ); + + void RemoveSelection(); + + void ResetSelection(); }; }} diff --git a/src/eepp/gaming/mapeditor/clayerproperties.cpp b/src/eepp/gaming/mapeditor/clayerproperties.cpp index b75131091..5b8257d01 100644 --- a/src/eepp/gaming/mapeditor/clayerproperties.cpp +++ b/src/eepp/gaming/mapeditor/clayerproperties.cpp @@ -180,7 +180,7 @@ cUIGridCell * cLayerProperties::CreateCell() { CellParams.Parent( mGenGrid->Container() ); cUITextInput::CreateParams TxtInputParams; - TxtInputParams.Flags = UI_CLIP_ENABLE | UI_VALIGN_CENTER | UI_AUTO_PADDING; + TxtInputParams.Flags = UI_CLIP_ENABLE | UI_VALIGN_CENTER | UI_AUTO_PADDING | UI_TEXT_SELECTION_ENABLED; TxtInputParams.MaxLength = LAYER_NAME_SIZE; cUIComplexControl::CreateParams CControl; diff --git a/src/eepp/gaming/mapeditor/cmapproperties.cpp b/src/eepp/gaming/mapeditor/cmapproperties.cpp index 045eeb894..d422d5b94 100644 --- a/src/eepp/gaming/mapeditor/cmapproperties.cpp +++ b/src/eepp/gaming/mapeditor/cmapproperties.cpp @@ -242,7 +242,7 @@ cUIGridCell * cMapProperties::CreateCell() { CellParams.Parent( mGenGrid->Container() ); cUITextInput::CreateParams TxtInputParams; - TxtInputParams.Flags = UI_CLIP_ENABLE | UI_VALIGN_CENTER | UI_AUTO_PADDING; + TxtInputParams.Flags = UI_CLIP_ENABLE | UI_VALIGN_CENTER | UI_AUTO_PADDING | UI_TEXT_SELECTION_ENABLED; TxtInputParams.MaxLength = LAYER_NAME_SIZE; cUIComplexControl::CreateParams CControl; diff --git a/src/eepp/gaming/mapeditor/cobjectproperties.cpp b/src/eepp/gaming/mapeditor/cobjectproperties.cpp index 7f1b238cd..4aa350287 100644 --- a/src/eepp/gaming/mapeditor/cobjectproperties.cpp +++ b/src/eepp/gaming/mapeditor/cobjectproperties.cpp @@ -181,7 +181,7 @@ cUIGridCell * cObjectProperties::CreateCell() { CellParams.Parent( mGenGrid->Container() ); cUITextInput::CreateParams TxtInputParams; - TxtInputParams.Flags = UI_CLIP_ENABLE | UI_VALIGN_CENTER | UI_AUTO_PADDING; + TxtInputParams.Flags = UI_CLIP_ENABLE | UI_VALIGN_CENTER | UI_AUTO_PADDING | UI_TEXT_SELECTION_ENABLED; TxtInputParams.MaxLength = LAYER_NAME_SIZE; cUIComplexControl::CreateParams CControl; diff --git a/src/eepp/ui/cuitextbox.cpp b/src/eepp/ui/cuitextbox.cpp index 1effccd4c..14d69aaaa 100644 --- a/src/eepp/ui/cuitextbox.cpp +++ b/src/eepp/ui/cuitextbox.cpp @@ -307,9 +307,14 @@ Uint32 cUITextBox::OnMouseDown( const eeVector2i& Pos, const Uint32 Flags ) { } void cUITextBox::DrawSelection() { - if ( IsTextSelectionEnabled() && SelCurInit() != SelCurEnd() ) { + if ( SelCurInit() != SelCurEnd() ) { Int32 init = eemin( SelCurInit(), SelCurEnd() ); Int32 end = eemax( SelCurInit(), SelCurEnd() ); + + if ( init < 0 && end > (Int32)mTextCache->Text().size() ) { + return; + } + Int32 lastEnd = end; eeVector2i initPos, endPos; diff --git a/src/eepp/ui/cuitextinput.cpp b/src/eepp/ui/cuitextinput.cpp index b6910618b..6191366aa 100644 --- a/src/eepp/ui/cuitextinput.cpp +++ b/src/eepp/ui/cuitextinput.cpp @@ -17,6 +17,7 @@ cUITextInput::cUITextInput( const cUITextInput::CreateParams& Params ) : mTextBuffer.Start(); mTextBuffer.Active( false ); mTextBuffer.SupportFreeEditing( Params.SupportFreeEditing ); + mTextBuffer.TextSelectionEnabled( IsTextSelectionEnabled() ); mTextBuffer.MaxLength( Params.MaxLength ); mTextBuffer.SetReturnCallback( cb::Make0( this, &cUITextInput::PrivOnPressEnter ) ); diff --git a/src/eepp/window/cinputtextbuffer.cpp b/src/eepp/window/cinputtextbuffer.cpp index 0c0f31d22..a6dce2cb2 100755 --- a/src/eepp/window/cinputtextbuffer.cpp +++ b/src/eepp/window/cinputtextbuffer.cpp @@ -51,6 +51,8 @@ cInputTextBuffer::cInputTextBuffer( cWindow * window ) : AutoPrompt( true ); + TextSelectionEnabled( false ); + SupportCopyPaste( true ); } @@ -92,6 +94,8 @@ void cInputTextBuffer::PromptToLeftFirstNoChar() { } else { mPromptPos = 0; } + + ResetSelection(); } void cInputTextBuffer::PromptToRightFirstNoChar() { @@ -108,9 +112,18 @@ void cInputTextBuffer::PromptToRightFirstNoChar() { mPromptPos = s; } } + + ResetSelection(); } -void cInputTextBuffer::EraseToNextNoChar() { +void cInputTextBuffer::ResetSelection() { + if ( TextSelectionEnabled() ) { + SelCurInit( -1 ); + SelCurEnd( -1 ); + } +} + +void cInputTextBuffer::EraseToPrevNoChar() { if ( !mText.size() || !mPromptPos ) return; @@ -133,9 +146,39 @@ void cInputTextBuffer::EraseToNextNoChar() { c = mText[ mPromptPos - 1 ]; } while ( String::IsLetter( c ) || String::IsNumber( c ) ); + ResetSelection(); + ChangedSinceLastUpdate( true ); } +void cInputTextBuffer::EraseToNextNoChar() { + if ( !mText.size() ) + return; + + Int32 tPromptPos = mPromptPos; + Int32 c; + Int32 size = (Int32)mText.size(); + + do { + tPromptPos++; + + if ( tPromptPos < size ) { + c = mText[ tPromptPos ]; + } else { + break; + } + } while ( String::IsLetter( c ) || String::IsNumber( c ) ); + + if ( tPromptPos <= size ) { + String iniStr( mText.substr( 0, mPromptPos ) ); + String endStr( mText.substr( tPromptPos ) ); + + Buffer( iniStr + endStr ); + + ResetSelection(); + } +} + bool cInputTextBuffer::IsIgnoredChar( const Uint32& c ) { if ( mIgnoredChars.size() ) { for ( eeUint i = 0; i < mIgnoredChars.size(); i++ ) { @@ -170,6 +213,8 @@ bool cInputTextBuffer::ValidChar( const Uint32& c ) { void cInputTextBuffer::TryAddChar( const Uint32& c ) { if ( SupportFreeEditing() ) { if ( ValidChar( c ) ) { + RemoveSelection(); + ChangedSinceLastUpdate( true ); if ( AutoPrompt() ) { @@ -193,6 +238,27 @@ void cInputTextBuffer::TryAddChar( const Uint32& c ) { } } +void cInputTextBuffer::RemoveSelection() { + if ( TextSelectionEnabled() && -1 != mSelCurInit && -1 != mSelCurEnd ) { + Int32 size = (Int32)mText.size(); + + if ( mSelCurInit <= size && mSelCurInit <= size ) { + Int32 init = eemin( mSelCurInit, mSelCurEnd ); + Int32 end = eemax( mSelCurInit, mSelCurEnd ); + String iniStr( mText.substr( 0, init ) ); + String endStr( mText.substr( end ) ); + + Buffer( iniStr + endStr ); + + CurPos( init ); + + ResetSelection(); + } else { + ResetSelection(); + } + } +} + void cInputTextBuffer::Update( InputEvent* Event ) { if ( Active() ) { cInput * Input = mWindow->GetInput(); @@ -208,46 +274,34 @@ void cInputTextBuffer::Update( InputEvent* Event ) { } case InputEvent::KeyDown: { - if ( mSelCurInit >= 0 && mSelCurInit != mSelCurEnd ) { - if ( ( Event->key.keysym.mod & KEYMOD_CTRL ) && ( Event->key.keysym.sym == KEY_C || Event->key.keysym.sym == KEY_X ) ) { - Int32 init = eemin( mSelCurInit, mSelCurEnd ); - Int32 end = eemax( mSelCurInit, mSelCurEnd ); - std::string clipStr( mText.substr( init, end - init ).ToUtf8() ); - mWindow->GetClipboard()->SetText( clipStr ); - } else if ( ( String::IsCharacter( Event->key.keysym.sym ) || - ( Event->key.keysym.sym >= KEY_UP && Event->key.keysym.sym <= KEY_END ) ) && - !( Event->key.keysym.sym >= KEY_NUMLOCK && Event->key.keysym.sym <= KEY_COMPOSE ) - ) { - if ( ! ( Input->ShiftPressed() && ( Event->key.keysym.sym >= KEY_UP && Event->key.keysym.sym <= KEY_END ) ) ) { - SelCurInit( -1 ); - SelCurEnd( -1 ); - } - } - - if ( ( ( Event->key.keysym.sym & KEYMOD_LCTRL ) && - ( Event->key.keysym.sym == KEY_X || Event->key.keysym.sym == KEY_V ) ) || - Event->key.keysym.sym == KEY_DELETE - ) { - if ( -1 != mSelCurInit && -1 != mSelCurEnd ) { + if ( TextSelectionEnabled() ) { + if ( mSelCurInit >= 0 && mSelCurInit != mSelCurEnd ) { + if ( ( Event->key.keysym.mod & KEYMOD_CTRL ) && ( Event->key.keysym.sym == KEY_C || Event->key.keysym.sym == KEY_X ) ) { Int32 init = eemin( mSelCurInit, mSelCurEnd ); Int32 end = eemax( mSelCurInit, mSelCurEnd ); - String iniStr( mText.substr( 0, init ) ); - String endStr( mText.substr( end ) ); + std::string clipStr( mText.substr( init, end - init ).ToUtf8() ); + mWindow->GetClipboard()->SetText( clipStr ); + } else if ( ( Event->key.keysym.sym >= KEY_UP && Event->key.keysym.sym <= KEY_END ) && + !( Event->key.keysym.sym >= KEY_NUMLOCK && Event->key.keysym.sym <= KEY_COMPOSE ) + ) { + if ( ! ( Input->ShiftPressed() && ( Event->key.keysym.sym >= KEY_UP && Event->key.keysym.sym <= KEY_END ) ) ) { + ResetSelection(); + } + } - Buffer( iniStr + endStr ); - - CurPos( mSelCurInit ); - - SelCurInit( -1 ); - SelCurEnd( -1 ); + if ( ( ( Event->key.keysym.sym & KEYMOD_LCTRL ) && + ( Event->key.keysym.sym == KEY_X || Event->key.keysym.sym == KEY_V ) ) || + Event->key.keysym.sym == KEY_DELETE + ) { + RemoveSelection(); } } - } - if ( ( Event->key.keysym.mod & KEYMOD_CTRL ) && Event->key.keysym.sym == KEY_A ) { - SelCurInit( 0 ); - SelCurEnd( mText.size() ); - CurPos( mSelCurEnd ); + if ( ( Event->key.keysym.mod & KEYMOD_CTRL ) && Event->key.keysym.sym == KEY_A ) { + SelCurInit( 0 ); + SelCurEnd( mText.size() ); + CurPos( mSelCurEnd ); + } } if ( Input->ShiftPressed() || Input->ControlPressed() ) { @@ -289,7 +343,10 @@ void cInputTextBuffer::Update( InputEvent* Event ) { } else if ( c == KEY_RIGHT ) { PromptToRightFirstNoChar(); break; - } else if ( ( c == KEY_BACKSPACE || c == KEY_DELETE ) ) { + } else if ( c == KEY_BACKSPACE ) { + EraseToPrevNoChar(); + break; + } else if ( c == KEY_DELETE ) { EraseToNextNoChar(); break; } @@ -313,6 +370,8 @@ void cInputTextBuffer::Update( InputEvent* Event ) { mText.resize( mText.size() - 1 ); AutoPrompt( true ); } + + ResetSelection(); } } else if ( ( c == KEY_RETURN || c == KEY_KP_ENTER ) ) { if ( SupportNewLine() && CanAdd() ) { @@ -320,6 +379,8 @@ void cInputTextBuffer::Update( InputEvent* Event ) { mPromptPos++; + ResetSelection(); + ChangedSinceLastUpdate( true ); } @@ -397,13 +458,19 @@ void cInputTextBuffer::Update( InputEvent* Event ) { ShiftSelection( lPromtpPos ); } } else { + eeInt lPromtpPos = mPromptPos; + if ( c == KEY_END ) { AutoPrompt( true ); + + ShiftSelection( lPromtpPos ); } if ( c == KEY_HOME ) { mPromptPos = 0; AutoPrompt(false); + + ShiftSelection( lPromtpPos ); } } break; @@ -430,13 +497,21 @@ void cInputTextBuffer::Update( InputEvent* Event ) { } void cInputTextBuffer::ShiftSelection( const eeInt& lastPromtpPos ) { + if ( !TextSelectionEnabled() ) + return; + cInput * Input = mWindow->GetInput(); if ( Input->ShiftPressed() && !Input->ControlPressed() ) { if ( SelCurInit() != CurPos() ) { SelCurEnd( CurPos() ); } else { - SelCurInit( CurPos() ); + if ( SelCurInit() != CurPos() ) { + SelCurInit( CurPos() ); + } else { + ResetSelection(); + return; + } } if ( -1 == SelCurInit() ) { @@ -668,6 +743,14 @@ bool cInputTextBuffer::SupportCopyPaste() { return 0 != ( mFlags & ( 1 << INPUT_TB_SUPPORT_COPY_PASTE ) ); } +bool cInputTextBuffer::TextSelectionEnabled() { + return 0 != ( mFlags & ( 1 << INPUT_TB_TEXT_SELECTION_ENABLED ) ); +} + +void cInputTextBuffer::TextSelectionEnabled( const bool& enabled ) { + BitOp::WriteBitKey( &mFlags, INPUT_TB_TEXT_SELECTION_ENABLED, enabled == true ); +} + void cInputTextBuffer::CursorToEnd() { mPromptPos = mText.size(); } diff --git a/src/test/eetest.cpp b/src/test/eetest.cpp index 1f96d647d..7c74d0793 100644 --- a/src/test/eetest.cpp +++ b/src/test/eetest.cpp @@ -75,7 +75,7 @@ void cEETest::Init() { Scenes[4] = cb::Make0( this, &cEETest::Screen4 ); Scenes[5] = cb::Make0( this, &cEETest::Screen5 ); - InBuf.Start(); + //InBuf.Start(); InBuf.SupportNewLine( true ); SetRandomSeed( static_cast( Sys::GetSystemTime() * 1000 ) ); @@ -537,7 +537,7 @@ void cEETest::CreateUI() { cUITextBox::CreateParams TxtBoxParams; cUITextInput::CreateParams TxtInputParams; - TxtInputParams.Flags = UI_CLIP_ENABLE | UI_AUTO_PADDING | UI_VALIGN_CENTER; + TxtInputParams.Flags = UI_CLIP_ENABLE | UI_AUTO_PADDING | UI_VALIGN_CENTER | UI_TEXT_SELECTION_ENABLED; cUIGfx::CreateParams TxtGfxParams; TxtGfxParams.Flags = UI_VALIGN_CENTER | UI_HALIGN_CENTER; @@ -655,11 +655,11 @@ void cEETest::CreateDecoratedWindow() { cUITabWidget * TabWidget = mTheme->CreateTabWidget( mUIWindow->Container(), eeSize( 510, 250 ), eeVector2i( 10, 55 ), UI_HALIGN_CENTER | UI_VALIGN_CENTER | UI_ANCHOR_RIGHT | UI_ANCHOR_BOTTOM | UI_ANCHOR_LEFT | UI_ANCHOR_TOP ); - cUITextEdit * TEdit = mTheme->CreateTextEdit( TabWidget, eeSize(), eeVector2i(), UI_AUTO_PADDING ); + cUITextEdit * TEdit = mTheme->CreateTextEdit( TabWidget, eeSize(), eeVector2i() ); TEdit->Text( mBuda ); TabWidget->Add( "TextEdit", TEdit ); - cUITextBox * Txt = mTheme->CreateTextInput( TabWidget, eeSize(), eeVector2i(), UI_AUTO_PADDING | UI_AUTO_SHRINK_TEXT | UI_TEXT_SELECTION_ENABLED ); + cUITextInput * Txt = mTheme->CreateTextInput( TabWidget, eeSize(), eeVector2i(), UI_AUTO_PADDING | UI_AUTO_SHRINK_TEXT | UI_TEXT_SELECTION_ENABLED ); Txt->Text( mBuda ); TabWidget->Add( "TextInput", Txt ); @@ -1317,21 +1317,23 @@ void cEETest::Render() { mInfoText.Draw( 6.f, 6.f ); - Uint32 NLPos = 0; - Uint32 LineNum = InBuf.GetCurPosLinePos( NLPos ); - if ( InBuf.CurPos() == (eeInt)InBuf.Buffer().size() && !LineNum ) { - FF2->Draw( "_", 6.f + FF2->GetTextWidth(), 180.f ); - } else { - FF2->SetText( InBuf.Buffer().substr( NLPos, InBuf.CurPos() - NLPos ) ); - FF2->Draw( "_", 6.f + FF2->GetTextWidth(), 180.f + (eeFloat)LineNum * (eeFloat)FF2->GetFontHeight() ); + if ( InBuf.Active() ) { + Uint32 NLPos = 0; + Uint32 LineNum = InBuf.GetCurPosLinePos( NLPos ); + if ( InBuf.CurPos() == (eeInt)InBuf.Buffer().size() && !LineNum ) { + FF2->Draw( "_", 6.f + FF2->GetTextWidth(), 180.f ); + } else { + FF2->SetText( InBuf.Buffer().substr( NLPos, InBuf.CurPos() - NLPos ) ); + FF2->Draw( "_", 6.f + FF2->GetTextWidth(), 180.f + (eeFloat)LineNum * (eeFloat)FF2->GetFontHeight() ); + } + + FF2->SetText( "FPS: " + String::ToStr( mWindow->FPS() ) ); + FF2->Draw( mWindow->GetWidth() - FF2->GetTextWidth() - 15, 0 ); + + FF2->SetText( InBuf.Buffer() ); + FF2->Draw( 6, 180, FONT_DRAW_SHADOW ); } - FF2->SetText( "FPS: " + String::ToStr( mWindow->FPS() ) ); - FF2->Draw( mWindow->GetWidth() - FF2->GetTextWidth() - 15, 0 ); - - FF2->SetText( InBuf.Buffer() ); - FF2->Draw( 6, 180, FONT_DRAW_SHADOW ); - cUIManager::instance()->Draw(); cUIManager::instance()->Update();