add initial examples, replacing the 'Demos/Demos3'. Will make it work cross-platform, OpenGL3/OpenGL2 and add more examples to it.
This commit is contained in:
411
examples/ThirdPartyLibs/Gwen/Controls/TextBox.cpp
Normal file
411
examples/ThirdPartyLibs/Gwen/Controls/TextBox.cpp
Normal file
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
GWEN
|
||||
Copyright (c) 2010 Facepunch Studios
|
||||
See license in Gwen.h
|
||||
*/
|
||||
|
||||
|
||||
#include "Gwen/Gwen.h"
|
||||
#include "Gwen/Controls/TextBox.h"
|
||||
#include "Gwen/Skin.h"
|
||||
#include "Gwen/Utility.h"
|
||||
#include "Gwen/Platform.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
using namespace Gwen;
|
||||
using namespace Gwen::Controls;
|
||||
|
||||
GWEN_CONTROL_CONSTRUCTOR( TextBox )
|
||||
{
|
||||
SetSize( 200, 20 );
|
||||
|
||||
SetMouseInputEnabled( true );
|
||||
SetKeyboardInputEnabled( true );
|
||||
|
||||
SetAlignment( Pos::Left | Pos::CenterV );
|
||||
SetTextPadding( Padding( 4, 2, 4, 2 ) );
|
||||
|
||||
m_iCursorPos = 0;
|
||||
m_iCursorEnd = 0;
|
||||
m_bSelectAll = false;
|
||||
|
||||
SetTextColor( Gwen::Color( 50, 50, 50, 255 ) ); // TODO: From Skin
|
||||
|
||||
SetTabable( true );
|
||||
|
||||
AddAccelerator( L"Ctrl + c", &TextBox::OnCopy );
|
||||
AddAccelerator( L"Ctrl + x", &TextBox::OnCut );
|
||||
AddAccelerator( L"Ctrl + v", &TextBox::OnPaste );
|
||||
AddAccelerator( L"Ctrl + a", &TextBox::OnSelectAll );
|
||||
}
|
||||
|
||||
bool TextBox::OnChar( Gwen::UnicodeChar c )
|
||||
{
|
||||
if ( c == '\t' ) return false;
|
||||
|
||||
Gwen::UnicodeString str;
|
||||
str += c;
|
||||
|
||||
InsertText( str );
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextBox::InsertText( const Gwen::UnicodeString& strInsert )
|
||||
{
|
||||
// TODO: Make sure fits (implement maxlength)
|
||||
|
||||
if ( HasSelection() )
|
||||
{
|
||||
EraseSelection();
|
||||
}
|
||||
|
||||
if ( m_iCursorPos > TextLength() ) m_iCursorPos = TextLength();
|
||||
|
||||
if ( !IsTextAllowed( strInsert, m_iCursorPos ) )
|
||||
return;
|
||||
|
||||
UnicodeString str = GetText();
|
||||
str.insert( m_iCursorPos, strInsert );
|
||||
SetText( str );
|
||||
|
||||
m_iCursorPos += (int) strInsert.size();
|
||||
m_iCursorEnd = m_iCursorPos;
|
||||
|
||||
RefreshCursorBounds();
|
||||
}
|
||||
|
||||
void TextBox::Render( Skin::Base* skin )
|
||||
{
|
||||
if ( ShouldDrawBackground() )
|
||||
skin->DrawTextBox( this );
|
||||
|
||||
|
||||
if ( !HasFocus() ) return;
|
||||
|
||||
// Draw selection.. if selected..
|
||||
if ( m_iCursorPos != m_iCursorEnd )
|
||||
{
|
||||
skin->GetRender()->SetDrawColor( Gwen::Color( 50, 170, 255, 200 ) );
|
||||
skin->GetRender()->DrawFilledRect( m_rectSelectionBounds );
|
||||
}
|
||||
|
||||
// Draw caret
|
||||
if ( fmod( Gwen::Platform::GetTimeInSeconds()-m_fLastInputTime, 1.0f ) > 0.5f )
|
||||
skin->GetRender()->SetDrawColor( Gwen::Color( 255, 255, 255, 255 ) );
|
||||
else
|
||||
skin->GetRender()->SetDrawColor( Gwen::Color( 0, 0, 0, 255 ) );
|
||||
|
||||
skin->GetRender()->DrawFilledRect( m_rectCaretBounds );
|
||||
}
|
||||
|
||||
void TextBox::RefreshCursorBounds()
|
||||
{
|
||||
m_fLastInputTime = Gwen::Platform::GetTimeInSeconds();
|
||||
|
||||
MakeCaratVisible();
|
||||
|
||||
Gwen::Point pA = GetCharacterPosition( m_iCursorPos );
|
||||
Gwen::Point pB = GetCharacterPosition( m_iCursorEnd );
|
||||
|
||||
m_rectSelectionBounds.x = Utility::Min( pA.x, pB.x );
|
||||
m_rectSelectionBounds.y = m_Text->Y() - 1;
|
||||
m_rectSelectionBounds.w = Utility::Max( pA.x, pB.x ) - m_rectSelectionBounds.x;
|
||||
m_rectSelectionBounds.h = m_Text->Height() + 2;
|
||||
|
||||
m_rectCaretBounds.x = pA.x;
|
||||
m_rectCaretBounds.y = m_Text->Y() - 1;
|
||||
m_rectCaretBounds.w = 1;
|
||||
m_rectCaretBounds.h = m_Text->Height() + 2;
|
||||
|
||||
Redraw();
|
||||
}
|
||||
|
||||
|
||||
void TextBox::OnPaste( Gwen::Controls::Base* /*pCtrl*/ )
|
||||
{
|
||||
InsertText( Platform::GetClipboardText() );
|
||||
}
|
||||
|
||||
void TextBox::OnCopy( Gwen::Controls::Base* /*pCtrl*/ )
|
||||
{
|
||||
if ( !HasSelection() ) return;
|
||||
|
||||
Platform::SetClipboardText( GetSelection() );
|
||||
}
|
||||
|
||||
void TextBox::OnCut( Gwen::Controls::Base* /*pCtrl*/ )
|
||||
{
|
||||
if ( !HasSelection() ) return;
|
||||
|
||||
Platform::SetClipboardText( GetSelection() );
|
||||
EraseSelection();
|
||||
}
|
||||
|
||||
void TextBox::OnSelectAll( Gwen::Controls::Base* /*pCtrl*/ )
|
||||
{
|
||||
m_iCursorEnd = 0;
|
||||
m_iCursorPos = TextLength();
|
||||
|
||||
RefreshCursorBounds();
|
||||
}
|
||||
|
||||
void TextBox::OnMouseDoubleClickLeft( int /*x*/, int /*y*/ )
|
||||
{
|
||||
OnSelectAll( this );
|
||||
}
|
||||
|
||||
UnicodeString TextBox::GetSelection()
|
||||
{
|
||||
if ( !HasSelection() ) return L"";
|
||||
|
||||
int iStart = Utility::Min( m_iCursorPos, m_iCursorEnd );
|
||||
int iEnd = Utility::Max( m_iCursorPos, m_iCursorEnd );
|
||||
|
||||
const UnicodeString& str = GetText();
|
||||
return str.substr( iStart, iEnd - iStart );
|
||||
}
|
||||
|
||||
bool TextBox::OnKeyReturn( bool bDown )
|
||||
{
|
||||
if ( bDown ) return true;
|
||||
|
||||
OnEnter();
|
||||
|
||||
// Try to move to the next control, as if tab had been pressed
|
||||
OnKeyTab( true );
|
||||
|
||||
// If we still have focus, blur it.
|
||||
if ( HasFocus() )
|
||||
{
|
||||
Blur();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextBox::OnKeyBackspace( bool bDown )
|
||||
{
|
||||
if ( !bDown ) return true;
|
||||
if ( HasSelection() )
|
||||
{
|
||||
EraseSelection();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( m_iCursorPos == 0 ) return true;
|
||||
|
||||
DeleteText( m_iCursorPos-1, 1 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextBox::OnKeyDelete( bool bDown )
|
||||
{
|
||||
if ( !bDown ) return true;
|
||||
if ( HasSelection() )
|
||||
{
|
||||
EraseSelection();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( m_iCursorPos >= TextLength() ) return true;
|
||||
|
||||
DeleteText( m_iCursorPos, 1 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextBox::OnKeyLeft( bool bDown )
|
||||
{
|
||||
if ( !bDown ) return true;
|
||||
|
||||
if ( m_iCursorPos > 0 )
|
||||
m_iCursorPos--;
|
||||
|
||||
if ( !Gwen::Input::IsShiftDown() )
|
||||
{
|
||||
m_iCursorEnd = m_iCursorPos;
|
||||
}
|
||||
|
||||
RefreshCursorBounds();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextBox::OnKeyRight( bool bDown )
|
||||
{
|
||||
if ( !bDown ) return true;
|
||||
|
||||
if ( m_iCursorPos < TextLength() )
|
||||
m_iCursorPos++;
|
||||
|
||||
if ( !Gwen::Input::IsShiftDown() )
|
||||
{
|
||||
m_iCursorEnd = m_iCursorPos;
|
||||
}
|
||||
|
||||
RefreshCursorBounds();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextBox::OnKeyHome( bool bDown )
|
||||
{
|
||||
if ( !bDown ) return true;
|
||||
m_iCursorPos = 0;
|
||||
|
||||
if ( !Gwen::Input::IsShiftDown() )
|
||||
{
|
||||
m_iCursorEnd = m_iCursorPos;
|
||||
}
|
||||
|
||||
RefreshCursorBounds();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextBox::OnKeyEnd( bool /*bDown*/ )
|
||||
{
|
||||
m_iCursorPos = TextLength();
|
||||
|
||||
if ( !Gwen::Input::IsShiftDown() )
|
||||
{
|
||||
m_iCursorEnd = m_iCursorPos;
|
||||
}
|
||||
|
||||
RefreshCursorBounds();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextBox::SetCursorPos( int i )
|
||||
{
|
||||
if ( m_iCursorPos == i ) return;
|
||||
|
||||
m_iCursorPos = i;
|
||||
RefreshCursorBounds();
|
||||
}
|
||||
|
||||
void TextBox::SetCursorEnd( int i )
|
||||
{
|
||||
if ( m_iCursorEnd == i ) return;
|
||||
|
||||
m_iCursorEnd = i;
|
||||
RefreshCursorBounds();
|
||||
}
|
||||
|
||||
|
||||
void TextBox::DeleteText( int iStartPos, int iLength )
|
||||
{
|
||||
UnicodeString str = GetText();
|
||||
str.erase( iStartPos, iLength );
|
||||
SetText( str );
|
||||
|
||||
if ( m_iCursorPos > iStartPos )
|
||||
{
|
||||
SetCursorPos( m_iCursorPos - iLength );
|
||||
}
|
||||
|
||||
SetCursorEnd( m_iCursorPos );
|
||||
}
|
||||
|
||||
bool TextBox::HasSelection()
|
||||
{
|
||||
return m_iCursorPos != m_iCursorEnd;
|
||||
}
|
||||
|
||||
void TextBox::EraseSelection()
|
||||
{
|
||||
int iStart = Utility::Min( m_iCursorPos, m_iCursorEnd );
|
||||
int iEnd = Utility::Max( m_iCursorPos, m_iCursorEnd );
|
||||
|
||||
DeleteText( iStart, iEnd - iStart );
|
||||
|
||||
// Move the cursor to the start of the selection,
|
||||
// since the end is probably outside of the string now.
|
||||
m_iCursorPos = iStart;
|
||||
m_iCursorEnd = iStart;
|
||||
}
|
||||
|
||||
void TextBox::OnMouseClickLeft( int x, int y, bool bDown )
|
||||
{
|
||||
if ( m_bSelectAll )
|
||||
{
|
||||
OnSelectAll( this );
|
||||
m_bSelectAll = false;
|
||||
return;
|
||||
}
|
||||
|
||||
int iChar = m_Text->GetClosestCharacter( m_Text->CanvasPosToLocal( Gwen::Point( x, y ) ) );
|
||||
|
||||
if ( bDown )
|
||||
{
|
||||
SetCursorPos( iChar );
|
||||
|
||||
if ( !Gwen::Input::IsShiftDown() )
|
||||
SetCursorEnd( iChar );
|
||||
|
||||
Gwen::MouseFocus = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( Gwen::MouseFocus == this )
|
||||
{
|
||||
SetCursorPos( iChar );
|
||||
Gwen::MouseFocus = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextBox::OnMouseMoved( int x, int y, int /*deltaX*/, int /*deltaY*/ )
|
||||
{
|
||||
if ( Gwen::MouseFocus != this ) return;
|
||||
|
||||
int iChar = m_Text->GetClosestCharacter( m_Text->CanvasPosToLocal( Gwen::Point( x, y ) ) );
|
||||
|
||||
SetCursorPos( iChar );
|
||||
}
|
||||
|
||||
void TextBox::MakeCaratVisible()
|
||||
{
|
||||
int iCaratPos = m_Text->GetCharacterPosition( m_iCursorPos ).x;
|
||||
|
||||
// If the carat is already in a semi-good position, leave it.
|
||||
{
|
||||
int iRealCaratPos = iCaratPos + m_Text->X();
|
||||
if ( iRealCaratPos > Width() * 0.1f && iRealCaratPos < Width() * 0.9f )
|
||||
return;
|
||||
}
|
||||
|
||||
// The ideal position is for the carat to be right in the middle
|
||||
int idealx = -iCaratPos + Width() * 0.5f;;
|
||||
|
||||
// Don't show too much whitespace to the right
|
||||
if ( idealx + m_Text->Width() < Width() - m_rTextPadding.right )
|
||||
idealx = -m_Text->Width() + (Width() - m_rTextPadding.right );
|
||||
|
||||
// Or the left
|
||||
if ( idealx > m_rTextPadding.left )
|
||||
idealx = m_rTextPadding.left;
|
||||
|
||||
m_Text->SetPos( idealx, m_Text->Y() );
|
||||
|
||||
}
|
||||
|
||||
void TextBox::Layout( Skin::Base* skin )
|
||||
{
|
||||
BaseClass::Layout( skin );
|
||||
|
||||
RefreshCursorBounds();
|
||||
}
|
||||
|
||||
void TextBox::OnTextChanged()
|
||||
{
|
||||
if ( m_iCursorPos > TextLength() ) m_iCursorPos = TextLength();
|
||||
if ( m_iCursorEnd > TextLength() ) m_iCursorEnd = TextLength();
|
||||
|
||||
onTextChanged.Call( this );
|
||||
}
|
||||
|
||||
void TextBox::OnEnter()
|
||||
{
|
||||
onReturnPressed.Call( this );
|
||||
}
|
||||
Reference in New Issue
Block a user