1853 lines
52 KiB
C++
1853 lines
52 KiB
C++
// Copyright (C) 2007 Id Software, Inc.
|
|
//
|
|
|
|
#ifndef __GAME_GUIS_USERINTERFACEEDITHELPER_H__
|
|
#define __GAME_GUIS_USERINTERFACEEDITHELPER_H__
|
|
|
|
|
|
template< class StrClass >
|
|
class sdClipboardConverter {
|
|
public:
|
|
static idWStr ToClipboard( const StrClass& toClipboard ) ;
|
|
static StrClass FromClipboard( const idWStr& clipboardText );
|
|
};
|
|
|
|
template<>
|
|
class sdClipboardConverter< idWStr > {
|
|
public:
|
|
static idWStr ToClipboard( const idWStr& toClipboard ) {
|
|
return toClipboard;
|
|
}
|
|
|
|
static idWStr FromClipboard( const idWStr& clipboardText ) {
|
|
return clipboardText;
|
|
}
|
|
};
|
|
|
|
template<>
|
|
class sdClipboardConverter< idStr > {
|
|
public:
|
|
static idWStr ToClipboard( const idStr& toClipboard ) {
|
|
return va( L"%hs", toClipboard.c_str() );
|
|
}
|
|
|
|
static idStr FromClipboard( const idWStr& clipboardText ) {
|
|
return va( "%ls", clipboardText.c_str() );
|
|
}
|
|
};
|
|
|
|
|
|
|
|
template< class CharType >
|
|
class sdCaseConverter {
|
|
public:
|
|
static CharType ToUpper( CharType c );
|
|
static CharType ToLower( CharType c );
|
|
};
|
|
|
|
template<>
|
|
class sdCaseConverter< wchar_t > {
|
|
public:
|
|
static wchar_t ToUpper( wchar_t c ) { return c; }
|
|
static wchar_t ToLower( wchar_t c ) { return c; }
|
|
};
|
|
|
|
template<>
|
|
class sdCaseConverter< char > {
|
|
public:
|
|
static char ToUpper( char c ) { return idStr::ToUpper( c ); }
|
|
static char ToLower( char c ) { return idStr::ToLower( c ); }
|
|
};
|
|
|
|
/*
|
|
============
|
|
sdTextLine
|
|
============
|
|
*/
|
|
class sdTextLine : public sdPoolAllocator< sdTextLine, sdPoolAllocator_DefaultIdentifier, 32 > {
|
|
public:
|
|
typedef idLinkList< sdTextLine > node_t;
|
|
sdTextLine( int start = 0, int end = 0, int cursor = -1 );
|
|
|
|
int GetCursor() const { return cursor; }
|
|
int GetStart() const { return start; }
|
|
int GetEnd() const { return end; }
|
|
|
|
int GetLength() const { return ( end - start ) + 1; }
|
|
|
|
int GetStringIndexForCursor() const;
|
|
|
|
bool HasCursor() const { return cursor >= 0 && cursor <= GetLength(); }
|
|
|
|
void SetCursorOnLine( int cursor );
|
|
sdTextLine* AdvanceCursor( int advance );
|
|
|
|
sdTextLine* MoveCursorUp();
|
|
sdTextLine* MoveCursorDown();
|
|
|
|
node_t& GetNode() { return node; }
|
|
const node_t& GetNode() const { return node; }
|
|
|
|
private:
|
|
void ClearCursor() { cursor = -1; }
|
|
|
|
private:
|
|
// start and end are both inclusive
|
|
// cursor is an offset in the string relative to start
|
|
int start;
|
|
int end;
|
|
int cursor;
|
|
|
|
node_t node;
|
|
};
|
|
|
|
|
|
/*
|
|
============
|
|
sdTextLine::sdTextLine
|
|
============
|
|
*/
|
|
ID_INLINE sdTextLine::sdTextLine( int start, int end, int cursor ) :
|
|
start( start ),
|
|
end( end ),
|
|
cursor( cursor ) {
|
|
node.SetOwner( this );
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
sdTextLine::SetCursorOnLine
|
|
============
|
|
*/
|
|
ID_INLINE void sdTextLine::SetCursorOnLine( int cursor ) {
|
|
sdTextLine* line = GetNode().ListHead()->Next();
|
|
while( line != NULL ) {
|
|
line->ClearCursor();
|
|
line = line->GetNode().Next();
|
|
}
|
|
this->cursor = idMath::ClampInt( 0, GetNode().Next() == NULL ? GetLength() - 1 : GetLength(), cursor );
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdTextLine::AdvanceCursor
|
|
============
|
|
*/
|
|
ID_INLINE sdTextLine* sdTextLine::AdvanceCursor( int advance ) {
|
|
assert( HasCursor() );
|
|
|
|
sdTextLine* newLine = this;
|
|
|
|
int newCursor = cursor + advance;
|
|
int newTextCursor = start + newCursor;
|
|
if( advance < 0 ) {
|
|
// move to the previous line if necessary
|
|
if( newTextCursor < start ) {
|
|
if( node.Prev() != NULL ) {
|
|
node.Prev()->SetCursorOnLine( node.Prev()->GetLength() );
|
|
if( newTextCursor == start - 1 ) {
|
|
newLine = node.Prev();
|
|
} else {
|
|
newLine = node.Prev()->AdvanceCursor( newTextCursor - start );
|
|
}
|
|
} else {
|
|
SetCursorOnLine( 0 );
|
|
}
|
|
} else {
|
|
SetCursorOnLine( newCursor );
|
|
}
|
|
} else if( advance > 0 ) {
|
|
// move to the next line if necessary
|
|
// catch the case where the move is exactly to the end of the line
|
|
if( newTextCursor > end && newTextCursor != end + 1 ) {
|
|
if( node.Next() != NULL ) {
|
|
node.Next()->SetCursorOnLine( 0 );
|
|
int advanceLocal = newTextCursor - node.Next()->start;
|
|
newLine = node.Next()->AdvanceCursor( advanceLocal );
|
|
} else {
|
|
SetCursorOnLine( GetLength() - 1 );
|
|
}
|
|
} else {
|
|
SetCursorOnLine( newCursor );
|
|
}
|
|
}
|
|
return newLine;
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdTextLine::MoveCursorUp
|
|
============
|
|
*/
|
|
ID_INLINE sdTextLine* sdTextLine::MoveCursorUp() {
|
|
assert( HasCursor() );
|
|
|
|
sdTextLine* prev = GetNode().Prev();
|
|
if( prev == NULL ) {
|
|
return this;
|
|
}
|
|
|
|
int cursorOffset = Min( prev->GetLength(), GetCursor() );
|
|
prev->SetCursorOnLine( cursorOffset );
|
|
|
|
return prev;
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdTextLine::MoveCursorDown
|
|
============
|
|
*/
|
|
ID_INLINE sdTextLine* sdTextLine::MoveCursorDown() {
|
|
assert( HasCursor() );
|
|
|
|
sdTextLine* next = GetNode().Next();
|
|
if( next == NULL ) {
|
|
return this;
|
|
}
|
|
|
|
int cursorOffset = Min( next->GetLength(), GetCursor() );
|
|
next->SetCursorOnLine( cursorOffset );
|
|
|
|
return next;
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdTextLine::GetStringIndexForCursor
|
|
============
|
|
*/
|
|
ID_INLINE int sdTextLine::GetStringIndexForCursor() const {
|
|
assert( HasCursor() );
|
|
return start + cursor;
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
class sdUIEditHelper {
|
|
public:
|
|
class sdUIEditEvent {
|
|
public:
|
|
enum type_e {
|
|
EE_DRAG_MOVE,
|
|
EE_MOUSE,
|
|
EE_SELECT_CANCEL,
|
|
EE_SELECT_ALL,
|
|
EE_MOVE_CURSOR,
|
|
EE_BACKSPACE,
|
|
EE_DELETE,
|
|
EE_UNDO,
|
|
EE_CLEAR,
|
|
EE_COPY,
|
|
EE_CUT,
|
|
EE_PASTE,
|
|
EE_CHAR,
|
|
EE_NEWLINE,
|
|
EE_INSERT_TEXT,
|
|
EE_COMPOSITION_CURSOR_SET,
|
|
EE_COMPOSITION_COMMIT
|
|
};
|
|
|
|
enum flags_e {
|
|
EF_SHIFT_PRESSED = BITT< 0 >::VALUE,
|
|
EF_CTRL_PRESSED = BITT< 1 >::VALUE
|
|
};
|
|
|
|
sdUIEditEvent() :
|
|
dataSize( 0 ),
|
|
data( NULL ) {
|
|
}
|
|
~sdUIEditEvent() {
|
|
FreeData();
|
|
}
|
|
|
|
void Init( type_e type, int value = 0, int value2 = 0, int value3 = 0, int value4 = 0, int flags = 0, size_t dataSize = 0, void* data = NULL ) {
|
|
FreeData();
|
|
|
|
this->type = type;
|
|
|
|
this->value = value;
|
|
this->value2 = value2;
|
|
this->value3 = value3;
|
|
this->value4 = value4;
|
|
|
|
this->flags = flags;
|
|
|
|
this->dataSize = dataSize;
|
|
this->data = data;
|
|
|
|
node.SetOwner( this );
|
|
}
|
|
|
|
void FreeData() {
|
|
Mem_Free( data );
|
|
data = NULL;
|
|
dataSize = 0;
|
|
}
|
|
|
|
type_e GetType() const { return type; }
|
|
|
|
idLinkList< sdUIEditEvent >& GetNode() { return node; }
|
|
|
|
// flags
|
|
bool ShiftPressed() const { return ( flags & EF_SHIFT_PRESSED ) != 0; }
|
|
bool CtrlPressed() const { return ( flags & EF_CTRL_PRESSED ) != 0; }
|
|
|
|
// EE_DRAG_MOVE, EE_MOUSE
|
|
float GetCursorX() const { return *reinterpret_cast<const float *>( &value3 ); }
|
|
float GetCursorY() const { return *reinterpret_cast<const float *>( &value4 ); }
|
|
|
|
// EE_MOUSE
|
|
mouseButton_t GetMouseButton() const { return static_cast< mouseButton_t >( value ); }
|
|
bool IsButtonDown() const { return ( value2 & 0x1 ) != 0; }
|
|
|
|
// EE_MOVE_CURSOR
|
|
enum cursoreMoveOp_e {
|
|
MC_HOME,
|
|
MC_END,
|
|
MC_UP,
|
|
MC_DOWN,
|
|
MC_RIGHT,
|
|
MC_LEFT,
|
|
MC_PAGE_UP,
|
|
MC_PAGE_DOWN
|
|
};
|
|
cursoreMoveOp_e GetCursorMoveOp() const { return static_cast< cursoreMoveOp_e >( value ); }
|
|
|
|
// EE_CHAR
|
|
CharType GetChar( void ) const { return static_cast< CharType >( value ); }
|
|
|
|
// EE_INSERT_TEXT, EE_COMPOSITION_COMMIT
|
|
const CharType* GetText() const { return reinterpret_cast< const CharType* >( data ); }
|
|
|
|
protected:
|
|
type_e type;
|
|
int value;
|
|
int value2;
|
|
int value3;
|
|
int value4;
|
|
int flags;
|
|
|
|
size_t dataSize; // bytes of data pointed to by data
|
|
void* data; // this must be manually freed if not NULL
|
|
|
|
idLinkList< sdUIEditEvent > node;
|
|
};
|
|
|
|
public:
|
|
static const int MAX_TEXT_LENGTH = 1024; // keep users from causing an allocation failure by pasting an excessive number of characters into an uncapped dialog
|
|
|
|
sdUIEditHelper();
|
|
~sdUIEditHelper();
|
|
|
|
void Init( UIEditClass* parent );
|
|
|
|
bool PostEvent( bool retVal, const sdSysEvent* event );
|
|
void DrawLocal();
|
|
void DrawText( const idVec4& color );
|
|
void OnGainFocus();
|
|
|
|
void ApplyLayout();
|
|
|
|
void MakeTextDirty() { textDirty = true; }
|
|
void TextChanged();
|
|
void ClearText();
|
|
|
|
void InsertText( const CharType* text );
|
|
void SurroundSelection( const CharType* prefix, const CharType* suffix );
|
|
bool GetSelectionRange( int& start, int& end ) const;
|
|
void SelectAll();
|
|
|
|
void QueueEvent( typename sdUIEditEvent::type_e type, int value = 0, int value2 = 0, int value3 = 0, int value4 = 0, int flags = 0, size_t dataSize = 0, void* data = NULL );
|
|
|
|
private:
|
|
int EraseSelection();
|
|
bool SelectionActive() const { return currentLine->GetStringIndexForCursor() != selectionStart && selectionStart != -1; }
|
|
void CancelSelection() { selectionStart = -1; }
|
|
void SaveUndo() { undoText = parent->editText; undoCursorPosition = currentLine->GetStringIndexForCursor(); undoAvailable = true; }
|
|
void Undo() { if( undoAvailable ) { parent->editText = undoText; currentLine = lines.Next(); currentLine = currentLine->AdvanceCursor( undoCursorPosition ); CursorChanged(); undoCursorPosition = -1; undoAvailable = false; } }
|
|
|
|
void MoveLeft();
|
|
void MoveRight();
|
|
|
|
void UpdateIndexByColorCodes( int start, int& index );
|
|
|
|
int GetMaxTextLength() { return ( parent->maxTextLength <= 0.0f ) ? MAX_TEXT_LENGTH : idMath::Ftoi( parent->maxTextLength.GetValue() ); }
|
|
|
|
void GetVisibleLines( sdTextLine*& firstVisible, sdTextLine*& lastVisible ) const;
|
|
sdTextLine* GetLineForPosition( const sdBounds2D& rect, const idVec2& pos ) const;
|
|
void CursorChanged( bool adjustVScroll = true );
|
|
bool CaptureChar( const CharType ch );
|
|
void InsertChar( CharType ch, int& cursorMove );
|
|
|
|
void DoInsertText( const CharType* text );
|
|
|
|
void ClearLines();
|
|
|
|
bool IsFirstLine() const { return currentLine == lines.Next(); }
|
|
bool IsLastLine() const { return currentLine == lines.Prev(); }
|
|
|
|
int GetCurrentLineIndex() const;
|
|
|
|
void FreeEvent( const sdUIEditEvent* ev );
|
|
const sdUIEditEvent* GetEvent();
|
|
void ProcessEvent( const sdUIEditEvent& ev );
|
|
void RunEventLoop();
|
|
|
|
private:
|
|
UIEditClass* parent;
|
|
|
|
// cursor
|
|
idVec2 cursorDrawPosition;
|
|
|
|
int cursorDrawTime;
|
|
bool drawCursor;
|
|
|
|
// composing
|
|
int compositionCursor;
|
|
|
|
// selection/scrolling
|
|
int selectionStart;
|
|
float drawOffset;
|
|
int mouseDownCursorPosition;
|
|
idVec2 mouseClick;
|
|
|
|
// undo
|
|
int undoCursorPosition;
|
|
StrClass undoText;
|
|
bool undoAvailable;
|
|
|
|
bool lastEventWasCharacter;
|
|
idWStr localText;
|
|
|
|
sdTextLine* currentLine;
|
|
|
|
int cursorMove;
|
|
|
|
sdTextDimensionHelper tdh;
|
|
|
|
idListGranularityOne< int > lineBreaks;
|
|
|
|
sdTextLine::node_t lines;
|
|
|
|
idLinkList< sdUIEditEvent > eventQueue;
|
|
idBlockAlloc< sdUIEditEvent, 16 > eventAllocator;
|
|
|
|
bool textDirty;
|
|
|
|
static const int CURSOR_FLASH_TIME = 400;
|
|
};
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::sdUIEditHelper
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
sdUIEditHelper< UIEditClass, StrClass, CharType >::sdUIEditHelper() :
|
|
compositionCursor( -1 ),
|
|
selectionStart( -1 ),
|
|
drawOffset( 0.0f ),
|
|
cursorDrawPosition( vec2_zero ),
|
|
undoAvailable( false ),
|
|
undoCursorPosition( 0 ),
|
|
mouseClick( -1.0f, -1.0f ),
|
|
mouseDownCursorPosition( -1 ),
|
|
lastEventWasCharacter( false ),
|
|
cursorDrawTime( 0 ),
|
|
drawCursor( true ),
|
|
cursorMove( 0 ),
|
|
currentLine( new sdTextLine( 0, 0, 0 ) ),
|
|
textDirty( false ) {
|
|
|
|
currentLine->GetNode().AddToEnd( lines );
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::~sdUIEditHelper
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
sdUIEditHelper< UIEditClass, StrClass, CharType >::~sdUIEditHelper() {
|
|
ClearLines();
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::ClearLines
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::ClearLines() {
|
|
while( !lines.IsListEmpty() ) {
|
|
delete lines.Next();
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::Init
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::Init( UIEditClass* parent ) {
|
|
this->parent = parent;
|
|
TextChanged();
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::PostEvent
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
bool sdUIEditHelper< UIEditClass, StrClass, CharType >::PostEvent( bool retVal, const sdSysEvent* event ) {
|
|
bool shiftPressed = keyInputManager->IsDown( K_SHIFT ) || keyInputManager->IsDown( K_RIGHT_SHIFT );
|
|
bool ctrlPressed = keyInputManager->IsDown( K_CTRL ) || keyInputManager->IsDown( K_RIGHT_CTRL );
|
|
int flags = ( shiftPressed ? sdUIEditEvent::EF_SHIFT_PRESSED : 0 ) | ( ctrlPressed ? sdUIEditEvent::EF_CTRL_PRESSED : 0 );
|
|
|
|
if ( event->IsMouseEvent() ) {
|
|
QueueEvent( sdUIEditEvent::EE_DRAG_MOVE, 0, 0, *reinterpret_cast<const int *>( &parent->GetUI()->cursorPos.GetValue().x ), *reinterpret_cast<const int *>( &parent->GetUI()->cursorPos.GetValue().y ) );
|
|
} else if ( event->IsMouseButtonEvent() && parent->GetUI()->IsFocused( parent ) ) {
|
|
QueueEvent( sdUIEditEvent::EE_MOUSE, event->GetMouseButton(), event->IsButtonDown(), *reinterpret_cast<const int *>( &parent->GetUI()->cursorPos.GetValue().x ), *reinterpret_cast<const int *>( &parent->GetUI()->cursorPos.GetValue().y ), flags );
|
|
|
|
mouseButton_t mb = event->GetMouseButton();
|
|
|
|
switch( mb ) {
|
|
case M_MOUSE1: // FALL THROUGH
|
|
case M_MOUSE2: // FALL THROUGH
|
|
case M_MOUSE3: // FALL THROUGH
|
|
case M_MOUSE4: // FALL THROUGH
|
|
case M_MOUSE5: // FALL THROUGH
|
|
case M_MOUSE6: // FALL THROUGH
|
|
case M_MOUSE7: // FALL THROUGH
|
|
case M_MOUSE8:
|
|
case M_MOUSE9:
|
|
case M_MOUSE10:
|
|
case M_MOUSE11:
|
|
case M_MOUSE12:
|
|
retVal = true;
|
|
break;
|
|
case M_MWHEELUP:
|
|
if ( parent->TestFlag( UIEditClass::EF_MULTILINE ) ) {
|
|
retVal = true;
|
|
}
|
|
if ( parent->TestFlag( sdUIWindow::WF_CAPTURE_KEYS ) ) {
|
|
retVal = true;
|
|
}
|
|
break;
|
|
case M_MWHEELDOWN:
|
|
if ( parent->TestFlag( UIEditClass::EF_MULTILINE ) ) {
|
|
retVal = true;
|
|
}
|
|
if ( parent->TestFlag( sdUIWindow::WF_CAPTURE_KEYS ) ) {
|
|
retVal = true;
|
|
}
|
|
break;
|
|
}
|
|
} else if ( event->IsKeyEvent() && parent->GetUI()->IsFocused( parent ) ) {
|
|
|
|
keyNum_t key = event->GetKey();
|
|
|
|
if ( event->IsKeyDown() ) {
|
|
switch( key ) {
|
|
case K_ESCAPE:
|
|
QueueEvent( sdUIEditEvent::EE_SELECT_CANCEL );
|
|
retVal = true;
|
|
break;
|
|
case K_HOME:
|
|
QueueEvent( sdUIEditEvent::EE_MOVE_CURSOR, sdUIEditEvent::MC_HOME, 0, 0, 0, flags );
|
|
retVal = true;
|
|
break;
|
|
case K_END:
|
|
QueueEvent( sdUIEditEvent::EE_MOVE_CURSOR, sdUIEditEvent::MC_END, 0, 0, 0, flags );
|
|
retVal = true;
|
|
break;
|
|
case K_UPARROW:
|
|
QueueEvent( sdUIEditEvent::EE_MOVE_CURSOR, sdUIEditEvent::MC_UP, 0, 0, 0, flags );
|
|
retVal = true;
|
|
break;
|
|
case K_DOWNARROW:
|
|
QueueEvent( sdUIEditEvent::EE_MOVE_CURSOR, sdUIEditEvent::MC_DOWN, 0, 0, 0, flags );
|
|
retVal = true;
|
|
break;
|
|
case K_RIGHTARROW:
|
|
QueueEvent( sdUIEditEvent::EE_MOVE_CURSOR, sdUIEditEvent::MC_RIGHT, 0, 0, 0, flags );
|
|
retVal = true;
|
|
break;
|
|
case K_LEFTARROW:
|
|
QueueEvent( sdUIEditEvent::EE_MOVE_CURSOR, sdUIEditEvent::MC_LEFT, 0, 0, 0, flags );
|
|
retVal = true;
|
|
break;
|
|
case K_PGUP:
|
|
if ( parent->TestFlag( UIEditClass::EF_MULTILINE ) ) {
|
|
QueueEvent( sdUIEditEvent::EE_MOVE_CURSOR, sdUIEditEvent::MC_PAGE_UP );
|
|
}
|
|
break;
|
|
case K_PGDN:
|
|
if ( parent->TestFlag( UIEditClass::EF_MULTILINE ) ) {
|
|
QueueEvent( sdUIEditEvent::EE_MOVE_CURSOR, sdUIEditEvent::MC_PAGE_DOWN );
|
|
}
|
|
break;
|
|
case K_DEL:
|
|
if ( parent->readOnly == 0.0f ) {
|
|
QueueEvent( sdUIEditEvent::EE_DELETE );
|
|
}
|
|
|
|
retVal = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} else if( !parent->readOnly ) {
|
|
if ( ( event->IsCharEvent() ) && parent->GetUI()->IsFocused( parent ) ) {
|
|
// EE_CHAR + ch + ctrlPressed
|
|
CharType ch = event->GetChar();
|
|
if ( ch == '\r' ) {
|
|
ch = '\n';
|
|
}
|
|
|
|
#define TO_CTRL( character ) ( ( ( character ) - 'a' ) + 1 )
|
|
switch ( ch ) {
|
|
// ctrl-A through ctrl-Z map to ASCII characters 1 through 26
|
|
case TO_CTRL( 'z' ):
|
|
// Ctrl+Z = Undo
|
|
QueueEvent( sdUIEditEvent::EE_UNDO );
|
|
retVal = true;
|
|
break;
|
|
case TO_CTRL( 'l' ):
|
|
// Ctrl+L = Clear
|
|
QueueEvent( sdUIEditEvent::EE_CLEAR );
|
|
retVal = true;
|
|
break;
|
|
case TO_CTRL( 'a' ):
|
|
// Ctrl+A = Select All
|
|
QueueEvent( sdUIEditEvent::EE_SELECT_ALL );
|
|
retVal = true;
|
|
break;
|
|
case TO_CTRL( 'c' ):
|
|
case TO_CTRL( 'x' ):
|
|
// Ctrl+C = Copy, Ctrl+X = Cut
|
|
QueueEvent( sdUIEditEvent::EE_COPY );
|
|
if ( TO_CTRL( 'x' ) == ch ) {
|
|
QueueEvent( sdUIEditEvent::EE_CUT );
|
|
}
|
|
retVal = true;
|
|
break;
|
|
case TO_CTRL( 'v' ):
|
|
// Ctrl+V = Paste
|
|
QueueEvent( sdUIEditEvent::EE_PASTE );
|
|
retVal = true;
|
|
break;
|
|
case TO_CTRL( 'h' ):
|
|
// Ctrl+H = Backspace
|
|
if ( parent->readOnly == 0.0f ) {
|
|
QueueEvent( sdUIEditEvent::EE_BACKSPACE );
|
|
}
|
|
retVal = true;
|
|
break;
|
|
default:
|
|
if ( CaptureChar( ch ) ) {
|
|
QueueEvent( sdUIEditEvent::EE_CHAR, ch );
|
|
|
|
retVal = true;
|
|
}
|
|
break;
|
|
#undef TO_CTRL
|
|
}
|
|
}
|
|
} else if ( event->IsGuiEvent() ) {
|
|
if ( event->GetGuiAction() == ULI_MENU_NEWLINE ) {
|
|
// EE_NEWLINE
|
|
if ( CaptureChar( '\n' ) ) {
|
|
QueueEvent( sdUIEditEvent::EE_NEWLINE );
|
|
retVal = true;
|
|
}
|
|
}
|
|
if ( parent->TestFlag( sdUIWindow::WF_CAPTURE_KEYS ) ) {
|
|
retVal = true;
|
|
}
|
|
}
|
|
|
|
if ( !event->IsMouseEvent() && !event->IsMouseButtonEvent() ) {
|
|
if ( parent->TestFlag( sdUIWindow::WF_CAPTURE_KEYS ) && ( ( event->GetKey() < K_F1 || event->GetKey() > K_F15 ) || event->IsGuiEvent() ) ) {
|
|
retVal = true;
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::DrawLocal
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::ProcessEvent( const sdUIEditEvent& ev ) {
|
|
switch ( ev.GetType() ) {
|
|
case sdUIEditEvent::EE_DRAG_MOVE: {
|
|
if ( mouseDownCursorPosition != -1 ) {
|
|
if ( !SelectionActive() ) {
|
|
selectionStart = currentLine->GetStringIndexForCursor();
|
|
}
|
|
mouseClick.x = ev.GetCursorX();
|
|
mouseClick.y = ev.GetCursorY();
|
|
CursorChanged();
|
|
}
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_MOUSE: {
|
|
mouseButton_t mb = ev.GetMouseButton();
|
|
|
|
if ( !ev.IsButtonDown() ) {
|
|
switch ( mb ) {
|
|
case M_MOUSE1: // FALL THROUGH
|
|
case M_MOUSE2: // FALL THROUGH
|
|
case M_MOUSE3: // FALL THROUGH
|
|
case M_MOUSE4: // FALL THROUGH
|
|
case M_MOUSE5: // FALL THROUGH
|
|
case M_MOUSE6: // FALL THROUGH
|
|
case M_MOUSE7: // FALL THROUGH
|
|
case M_MOUSE8:
|
|
case M_MOUSE9:
|
|
case M_MOUSE10:
|
|
case M_MOUSE11:
|
|
case M_MOUSE12:
|
|
mouseDownCursorPosition = -1;
|
|
break;
|
|
}
|
|
} else {
|
|
switch ( mb ) {
|
|
case M_MOUSE1: // FALL THROUGH
|
|
case M_MOUSE2: // FALL THROUGH
|
|
case M_MOUSE3: // FALL THROUGH
|
|
case M_MOUSE4: // FALL THROUGH
|
|
case M_MOUSE5: // FALL THROUGH
|
|
case M_MOUSE6: // FALL THROUGH
|
|
case M_MOUSE7: // FALL THROUGH
|
|
case M_MOUSE8:
|
|
case M_MOUSE9:
|
|
case M_MOUSE10:
|
|
case M_MOUSE11:
|
|
case M_MOUSE12:
|
|
if ( !ev.ShiftPressed() && SelectionActive() ) {
|
|
CancelSelection();
|
|
}
|
|
mouseDownCursorPosition = currentLine->GetStringIndexForCursor();
|
|
mouseClick.x = ev.GetCursorX();
|
|
mouseClick.y = ev.GetCursorY();
|
|
CursorChanged();
|
|
break;
|
|
case M_MWHEELUP: {
|
|
sdTextLine* firstVisible = NULL;
|
|
sdTextLine* lastVisible = NULL;
|
|
GetVisibleLines( firstVisible, lastVisible );
|
|
if ( parent->scrollAmount.GetValue().y < 0.0f ) {
|
|
float amount = idMath::ClampInt( -parent->scrollAmountMax, 0.0f, parent->scrollAmount.GetValue().y + tdh.GetLineHeight() );
|
|
parent->scrollAmount.SetIndex( 1, amount );
|
|
CursorChanged( false );
|
|
}
|
|
break;
|
|
}
|
|
case M_MWHEELDOWN: {
|
|
sdTextLine* firstVisible = NULL;
|
|
sdTextLine* lastVisible = NULL;
|
|
GetVisibleLines( firstVisible, lastVisible );
|
|
|
|
if ( firstVisible != lastVisible ) {
|
|
float amount = idMath::ClampFloat( -parent->scrollAmountMax, 0.0f, parent->scrollAmount.GetValue().y - tdh.GetLineHeight() );
|
|
parent->scrollAmount.SetIndex( 1, amount );
|
|
CursorChanged( false );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_SELECT_CANCEL: {
|
|
CancelSelection();
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_MOVE_CURSOR: {
|
|
switch ( ev.GetCursorMoveOp() ) {
|
|
case sdUIEditEvent::MC_HOME:
|
|
if ( !ev.ShiftPressed() ) {
|
|
CancelSelection();
|
|
} else if ( !SelectionActive() ) {
|
|
selectionStart = currentLine->GetStringIndexForCursor();
|
|
}
|
|
|
|
if ( ev.CtrlPressed() || lineBreaks.Num() == 0 ) {
|
|
currentLine = lines.Next();
|
|
parent->scrollAmount = vec2_zero;
|
|
}
|
|
|
|
currentLine->SetCursorOnLine( 0 );
|
|
CursorChanged();
|
|
break;
|
|
case sdUIEditEvent::MC_END:
|
|
if ( !ev.ShiftPressed() ) {
|
|
CancelSelection();
|
|
} else if ( !SelectionActive() ) {
|
|
selectionStart = currentLine->GetStringIndexForCursor();
|
|
}
|
|
|
|
if ( ev.CtrlPressed() || lineBreaks.Num() == 0 ) {
|
|
currentLine = lines.Next();
|
|
currentLine->SetCursorOnLine( 0 );
|
|
currentLine = currentLine->AdvanceCursor( parent->editText.GetValue().Length() );
|
|
} else {
|
|
currentLine->SetCursorOnLine( currentLine->GetLength() );
|
|
}
|
|
|
|
CursorChanged();
|
|
break;
|
|
case sdUIEditEvent::MC_UP:
|
|
if ( !ev.ShiftPressed() ) {
|
|
if ( parent->TestFlag( UIEditClass::EF_MULTILINE ) == true ) {
|
|
CancelSelection();
|
|
}
|
|
} else if ( !SelectionActive() ) {
|
|
selectionStart = currentLine->GetStringIndexForCursor();
|
|
}
|
|
currentLine = currentLine->MoveCursorUp();
|
|
CursorChanged();
|
|
break;
|
|
case sdUIEditEvent::MC_DOWN:
|
|
if ( !ev.ShiftPressed() ) {
|
|
if( parent->TestFlag( UIEditClass::EF_MULTILINE ) == true ) {
|
|
CancelSelection();
|
|
}
|
|
} else if ( !SelectionActive() ) {
|
|
selectionStart = currentLine->GetStringIndexForCursor();
|
|
}
|
|
currentLine = currentLine->MoveCursorDown();
|
|
CursorChanged();
|
|
break;
|
|
case sdUIEditEvent::MC_RIGHT:
|
|
if ( !ev.ShiftPressed() ) {
|
|
CancelSelection();
|
|
} else if ( !SelectionActive() ) {
|
|
selectionStart = currentLine->GetStringIndexForCursor();
|
|
}
|
|
MoveRight();
|
|
break;
|
|
case sdUIEditEvent::MC_LEFT:
|
|
if ( !ev.ShiftPressed() ) {
|
|
CancelSelection();
|
|
} else if ( !SelectionActive() ) {
|
|
selectionStart = currentLine->GetStringIndexForCursor();
|
|
}
|
|
MoveLeft();
|
|
break;
|
|
case sdUIEditEvent::MC_PAGE_UP: {
|
|
sdBounds2D drawRect = parent->GetDrawRect();
|
|
float pageSize = drawRect.GetHeight();
|
|
float amount = idMath::ClampFloat( -parent->scrollAmountMax, 0.0f, parent->scrollAmount.GetValue().y + pageSize );
|
|
parent->scrollAmount.SetIndex( 1, amount );
|
|
CursorChanged( false );
|
|
break;
|
|
}
|
|
case sdUIEditEvent::MC_PAGE_DOWN: {
|
|
sdBounds2D drawRect = parent->GetDrawRect();
|
|
float pageSize = drawRect.GetHeight();
|
|
float amount = idMath::ClampFloat( -parent->scrollAmountMax, 0.0f, parent->scrollAmount.GetValue().y - pageSize );
|
|
parent->scrollAmount.SetIndex( 1, amount );
|
|
CursorChanged( false );
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_BACKSPACE: {
|
|
SaveUndo();
|
|
|
|
int index = currentLine->GetStringIndexForCursor();
|
|
if ( !SelectionActive() ) {
|
|
// the cursor is at the very end
|
|
if( index >= parent->editText.GetValue().Length() ) {
|
|
StrClass temp = parent->editText.GetValue().Mid( 0, parent->editText.GetValue().Length() - 1 );
|
|
parent->editText = temp;
|
|
} else {
|
|
cursorMove += Max( 0, index - 1 ) - index;
|
|
StrClass temp = parent->editText.GetValue().Mid( 0, index + cursorMove );
|
|
temp += parent->editText.GetValue().Mid( index, parent->editText.GetValue().Length() - index );
|
|
parent->editText = temp;
|
|
}
|
|
} else {
|
|
EraseSelection();
|
|
if ( selectionStart < index ) {
|
|
cursorMove += selectionStart - index;
|
|
}
|
|
}
|
|
|
|
lastEventWasCharacter = false;
|
|
CancelSelection(); // collapse the selection after the deletion
|
|
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_DELETE: {
|
|
SaveUndo();
|
|
|
|
int index = currentLine->GetStringIndexForCursor();
|
|
if ( !SelectionActive() ) {
|
|
StrClass temp = parent->editText.GetValue().Mid( 0, index );
|
|
temp += parent->editText.GetValue().Mid( index + 1, parent->editText.GetValue().Length() - index - 1 );
|
|
parent->editText = temp;
|
|
} else {
|
|
EraseSelection();
|
|
if ( selectionStart < index ) {
|
|
cursorMove += selectionStart - index;
|
|
}
|
|
}
|
|
|
|
lastEventWasCharacter = false;
|
|
CancelSelection(); // collapse the selection after the deletion
|
|
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_UNDO: {
|
|
Undo();
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_CLEAR: {
|
|
parent->ClearText();
|
|
cursorMove += -currentLine->GetStringIndexForCursor();
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_SELECT_ALL: {
|
|
SelectAll();
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_COPY: {
|
|
if ( SelectionActive() ) {
|
|
int selStart;
|
|
int selEnd;
|
|
GetSelectionRange( selStart, selEnd );
|
|
|
|
StrClass selectionText = parent->editText.GetValue().Mid( selStart, selEnd - selStart );
|
|
idWStr clipboardText;
|
|
if ( parent->password ) {
|
|
clipboardText.Fill( L'*', selectionText.Length() );
|
|
} else {
|
|
clipboardText = sdClipboardConverter< StrClass >::ToClipboard( selectionText );
|
|
}
|
|
|
|
sys->SetClipboardData( clipboardText.c_str() );
|
|
}
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_CUT: {
|
|
SaveUndo();
|
|
EraseSelection();
|
|
if ( selectionStart < currentLine->GetStringIndexForCursor() ) {
|
|
cursorMove += selectionStart - currentLine->GetStringIndexForCursor();
|
|
}
|
|
CancelSelection();
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_PASTE: {
|
|
SaveUndo();
|
|
|
|
idWStr pasteText = sys->GetClipboardData();
|
|
pasteText.Replace( L"\b", L"" );
|
|
pasteText.Replace( L"\t", L"" );
|
|
pasteText.Replace( L"\r", L"" );
|
|
|
|
if ( pasteText.Length() ) {
|
|
int numErased = 0;
|
|
if ( SelectionActive() ) {
|
|
numErased = EraseSelection();
|
|
}
|
|
|
|
int selStart;
|
|
int selEnd;
|
|
GetSelectionRange( selStart, selEnd );
|
|
StrClass clipboardTemp( sdClipboardConverter< StrClass >::FromClipboard( pasteText ) );
|
|
StrClass temp = parent->editText;
|
|
temp.Insert( clipboardTemp.c_str(), selEnd - numErased );
|
|
|
|
if ( parent->maxTextLength == 0.0f || temp.LengthWithoutColors() <= parent->maxTextLength ) {
|
|
if ( parent->TestFlag( UIEditClass::EF_UPPERCASE ) ) {
|
|
for ( int i = 0; i < temp.Length(); i++ ) {
|
|
temp[ i ] = sdCaseConverter< CharType >::ToUpper( temp[ i ] );
|
|
}
|
|
}
|
|
parent->editText = temp;
|
|
|
|
CancelSelection();
|
|
cursorMove += pasteText.Length();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_CHAR: {
|
|
CharType ch = ev.GetChar();
|
|
StrClass temp = parent->editText;
|
|
|
|
int selStart;
|
|
int selEnd;
|
|
|
|
GetSelectionRange( selStart, selEnd );
|
|
if ( selStart < selEnd ) {
|
|
temp.EraseRange( selStart, selEnd - selStart );
|
|
}
|
|
|
|
temp.Insert( ch, currentLine->GetStringIndexForCursor() - ( selEnd - selStart ) );
|
|
if ( parent->maxTextLength == 0.0f || temp.LengthWithoutColors() <= parent->maxTextLength ) {
|
|
InsertChar( ch, cursorMove );
|
|
}
|
|
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_NEWLINE: {
|
|
InsertChar( '\n', cursorMove );
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch ( ev.GetType() ) {
|
|
case sdUIEditEvent::EE_INSERT_TEXT: {
|
|
DoInsertText( ev.GetText() );
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_COMPOSITION_CURSOR_SET: {
|
|
compositionCursor = currentLine->GetStringIndexForCursor();
|
|
break;
|
|
}
|
|
case sdUIEditEvent::EE_COMPOSITION_COMMIT: {
|
|
if ( compositionCursor != -1 ) {
|
|
// commit composition text
|
|
currentLine = lines.Next();
|
|
currentLine->SetCursorOnLine( 0 );
|
|
currentLine = currentLine->AdvanceCursor( compositionCursor );
|
|
compositionCursor += StrClass::Length( ev.GetText() );
|
|
DoInsertText( ev.GetText() );
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if ( cursorMove != 0 && !ev.ShiftPressed() && SelectionActive() ) {
|
|
CancelSelection();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( textDirty ) {
|
|
TextChanged();
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::DrawLocal
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::DrawLocal() {
|
|
sdBounds2D rect = parent->GetDrawRect();
|
|
rect.GetMins() += parent->scrollAmount;
|
|
|
|
int textLength = localText.Length();
|
|
|
|
int now = parent->GetUI()->GetCurrentTime();
|
|
|
|
// Draw cursor
|
|
if ( parent->GetUI()->IsFocused( parent ) ) {
|
|
if( now > cursorDrawTime ) {
|
|
drawCursor = !drawCursor;
|
|
cursorDrawTime = now + CURSOR_FLASH_TIME;
|
|
}
|
|
if ( drawCursor ) {
|
|
float x = cursorDrawPosition.x;
|
|
float y = cursorDrawPosition.y;
|
|
float w = parent->cursor.width;
|
|
float h = tdh.GetLineHeight() ? tdh.GetLineHeight() : parent->cursor.height;
|
|
|
|
// highlight whole cursor text if present
|
|
const wchar_t* cursorText = parent->GetCursorText();
|
|
if ( *cursorText != L'\0' ) {
|
|
int currentCursor = currentLine->GetStringIndexForCursor() + cursorMove;
|
|
|
|
w = tdh.GetWidth( currentCursor, currentCursor );
|
|
|
|
idVec4 color( parent->foreColor.GetValue().x, parent->foreColor.GetValue().y, parent->foreColor.GetValue().z, 0.25f );
|
|
|
|
deviceContext->DrawClippedRect( x, y, w, h, color );
|
|
deviceContext->DrawClippedBox( x, y, w, h, 1.0f, parent->foreColor );
|
|
} else {
|
|
parent->DrawMaterial( parent->cursor.mi, x, y, w, h, parent->foreColor );
|
|
}
|
|
}
|
|
}
|
|
|
|
// selection highlight
|
|
if ( SelectionActive() ) {
|
|
int selectionStart = this->selectionStart;
|
|
int selectionEnd = currentLine->GetStringIndexForCursor();
|
|
if( selectionEnd < selectionStart ) {
|
|
Swap( selectionEnd, selectionStart );
|
|
}
|
|
|
|
sdTextLine* line = lines.Next();
|
|
|
|
float height = tdh.GetLineHeight();
|
|
idVec4 color( parent->foreColor.GetValue().x, parent->foreColor.GetValue().y, parent->foreColor.GetValue().z, 0.25f );
|
|
|
|
int i = 0;
|
|
sdBounds2D offsetRect;
|
|
while( line != NULL ) {
|
|
int begin = Max( selectionStart, line->GetStart() );
|
|
int end = Min( selectionEnd - 1, line->GetEnd() );
|
|
|
|
float width = tdh.GetWidth( begin, end );
|
|
float xOffset = tdh.GetWidth( line->GetStart(), line->GetStart() + ( begin - line->GetStart() - 1 ) );
|
|
|
|
offsetRect = rect;
|
|
offsetRect.TranslateSelf( xOffset, parent->lineHeight * i );
|
|
|
|
deviceContext->DrawClippedRect( offsetRect.GetMins().x, offsetRect.GetMins().y, width, height, color );
|
|
|
|
line = line->GetNode().Next();
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::DrawText
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::DrawText( const idVec4& color ) {
|
|
// edit text
|
|
if ( localText.Length() > 0 ) {
|
|
sdBounds2D rect = parent->GetDrawRect();
|
|
rect.GetMins() += parent->scrollAmount;
|
|
|
|
sdWStringBuilder_Heap builder;
|
|
|
|
sdTextLine* line = lines.Next();
|
|
int i = 0;
|
|
sdBounds2D offsetRect;
|
|
while( line != NULL ) {
|
|
int len = line->GetLength();
|
|
if( len > 0 ) {
|
|
builder = L"";
|
|
builder.Append( &localText[ line->GetStart() ], len );
|
|
|
|
offsetRect = rect;
|
|
offsetRect.TranslateSelf( 0.0f, parent->lineHeight * i );
|
|
parent->sdUIWindow::DrawText( builder.c_str(), color, parent->fontSize, offsetRect, parent->cachedFontHandle, parent->GetDrawTextFlags() );
|
|
}
|
|
line = line->GetNode().Next();
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::ClearText
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::ClearText() {
|
|
SaveUndo();
|
|
CancelSelection();
|
|
CursorChanged();
|
|
ClearLines();
|
|
currentLine = new sdTextLine( 0, 0, 0 );
|
|
currentLine->GetNode().AddToEnd( lines );
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::GetSelectionRange
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
bool sdUIEditHelper< UIEditClass, StrClass, CharType >::GetSelectionRange( int& selStart, int& selEnd ) const {
|
|
int stringIndex = currentLine->GetStringIndexForCursor() + cursorMove;
|
|
|
|
if ( !SelectionActive() ) {
|
|
selStart = stringIndex;
|
|
selEnd = stringIndex;
|
|
return false;
|
|
}
|
|
|
|
selStart = selectionStart == -1 ? stringIndex : selectionStart;
|
|
selEnd = selectionStart == -1 ? stringIndex + 1 : stringIndex;
|
|
if ( selEnd < selStart ) {
|
|
Swap( selEnd, selStart );
|
|
}
|
|
|
|
int len = parent->editText.GetValue().Length();
|
|
selStart = idMath::ClampInt( 0, len - 1, selStart );
|
|
selEnd = idMath::ClampInt( selStart, len, selEnd );
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::EraseSelection
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
int sdUIEditHelper< UIEditClass, StrClass, CharType >::EraseSelection() {
|
|
int selStart;
|
|
int selEnd;
|
|
GetSelectionRange( selStart, selEnd );
|
|
if ( selStart == selEnd ) {
|
|
return 0;
|
|
}
|
|
|
|
StrClass temp = parent->editText;
|
|
temp.EraseRange( selStart, selEnd - selStart );
|
|
parent->editText = temp;
|
|
|
|
return ( selEnd - selStart );
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::MoveLeft
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::MoveLeft() {
|
|
|
|
int cursorMove = -1;
|
|
// move to the previous word
|
|
const CharType* buffer = parent->editText.GetValue().c_str();
|
|
int len = StrClass::Length( buffer );
|
|
|
|
if ( keyInputManager->IsDown( K_CTRL ) || keyInputManager->IsDown( K_RIGHT_CTRL ) ) {
|
|
if( UIEditClass::CharIsPrintable( buffer[ currentLine->GetStringIndexForCursor() + cursorMove - 1 ] ) ) {
|
|
while ( ( ( currentLine->GetStringIndexForCursor() + cursorMove ) > 0 ) && UIEditClass::CharIsPrintable( buffer[ currentLine->GetStringIndexForCursor() + cursorMove - 1 ] ) ) {
|
|
cursorMove--;
|
|
}
|
|
} else {
|
|
// skip out of whitespace to a word
|
|
while ( ( ( currentLine->GetStringIndexForCursor() + cursorMove ) > 0 ) && !UIEditClass::CharIsPrintable( buffer[ currentLine->GetStringIndexForCursor() + cursorMove - 1 ] ) ) {
|
|
cursorMove--;
|
|
}
|
|
|
|
// now skip the word
|
|
while ( ( ( currentLine->GetStringIndexForCursor() + cursorMove ) > 0 ) && UIEditClass::CharIsPrintable( buffer[ currentLine->GetStringIndexForCursor() + cursorMove - 1 ] ) ) {
|
|
cursorMove--;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
currentLine = currentLine->AdvanceCursor( cursorMove );
|
|
CursorChanged();
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::MoveRight
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::MoveRight() {
|
|
int cursorMove = 1;
|
|
// move to the next word
|
|
const CharType* buffer = parent->editText.GetValue().c_str();
|
|
int len = StrClass::Length( buffer );
|
|
|
|
if ( keyInputManager->IsDown( K_CTRL ) || keyInputManager->IsDown( K_RIGHT_CTRL ) ) {
|
|
// skip out of the current word
|
|
while ( ( ( currentLine->GetStringIndexForCursor() + cursorMove ) < len ) && UIEditClass::CharIsPrintable( buffer[ currentLine->GetStringIndexForCursor() + cursorMove ] ) ) {
|
|
cursorMove++;
|
|
}
|
|
|
|
// skip whitespace
|
|
while ( ( ( currentLine->GetStringIndexForCursor() + cursorMove ) < len ) && !UIEditClass::CharIsPrintable( buffer[ currentLine->GetStringIndexForCursor() + cursorMove ] ) ) {
|
|
cursorMove++;
|
|
}
|
|
}
|
|
|
|
currentLine = currentLine->AdvanceCursor( cursorMove );
|
|
CursorChanged();
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::UpdateIndexByColorCodes
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::UpdateIndexByColorCodes( int start, int& index ) {
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::GetVisibleLines
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::GetVisibleLines( sdTextLine*& firstVisible, sdTextLine*& lastVisible ) const {
|
|
firstVisible = lastVisible = NULL;
|
|
|
|
sdBounds2D rect = parent->GetDrawRect();
|
|
|
|
firstVisible = lines.Prev();
|
|
|
|
int index = lines.Num();
|
|
while( firstVisible != NULL ) {
|
|
if( ( index * tdh.GetLineHeight() ) + parent->scrollAmount.GetValue().y <= 0.0f ) {
|
|
break;
|
|
}
|
|
index--;
|
|
firstVisible = firstVisible->GetNode().Prev();
|
|
}
|
|
if( firstVisible == NULL ) {
|
|
firstVisible = lines.Next();
|
|
index = 0;
|
|
}
|
|
|
|
lastVisible = firstVisible;
|
|
|
|
while( lastVisible != NULL ) {
|
|
if( ( ( index + 1 ) * tdh.GetLineHeight() ) + parent->scrollAmount.GetValue().y >= rect.GetHeight() ) {
|
|
break;
|
|
}
|
|
index++;
|
|
lastVisible = lastVisible->GetNode().Next();
|
|
}
|
|
if( lastVisible == NULL ) {
|
|
lastVisible = lines.Prev();
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::GetLineForPosition
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
sdTextLine* sdUIEditHelper< UIEditClass, StrClass, CharType >::GetLineForPosition( const sdBounds2D& rect, const idVec2& pos ) const {
|
|
if( pos.x < rect.GetMins().x ) {
|
|
return currentLine;
|
|
}
|
|
|
|
float rowHeight = tdh.GetLineHeight();
|
|
int index = 0;
|
|
sdTextLine* line = lines.Next();
|
|
|
|
while( line != NULL ) {
|
|
float rowBase = rect.GetMins().y + index * rowHeight;
|
|
if( rowBase < pos.y && pos.y < rowBase + rowHeight ) {
|
|
return line;
|
|
}
|
|
index++;
|
|
line = line->GetNode().Next();
|
|
}
|
|
return currentLine;
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::CursorChanged
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::CursorChanged( bool adjustVScroll ) {
|
|
int textLength = localText.Length();
|
|
|
|
idVec2 newCursorPos;
|
|
idVec2 tdhOffset;
|
|
|
|
sdBounds2D rect( parent->GetWorldRect() );
|
|
//rect.TranslateSelf( -rect.GetMins() );
|
|
sdBounds2D offsetRect( rect );
|
|
offsetRect.TranslateSelf( parent->scrollAmount );
|
|
|
|
if( mouseClick.x >= 0.0f && mouseClick.y >= 0.0f ) {
|
|
idVec2 offsetClick = mouseClick;
|
|
offsetClick -= parent->GetWorldRect().ToVec2();
|
|
|
|
sdTextLine* clickedRow = GetLineForPosition( offsetRect, mouseClick );
|
|
currentLine = clickedRow;
|
|
|
|
// see if the click is past the end of the line
|
|
float width = tdh.GetWidth( clickedRow->GetStart(), clickedRow->GetEnd() );
|
|
if ( offsetClick.x >= width ) {
|
|
clickedRow->SetCursorOnLine( clickedRow->GetLength() );
|
|
} else {
|
|
int i;
|
|
for ( i = clickedRow->GetStart(); i <= clickedRow->GetEnd(); i++ ) {
|
|
width = tdh.GetWidth( clickedRow->GetStart(), i - 1 );
|
|
float charWidth = tdh.ToVirtualScreenSizeFloat( tdh.GetAdvance( i ) );
|
|
float halfWidth = ( charWidth * 0.5f );
|
|
if ( ( offsetClick.x - halfWidth ) < ( width + parent->scrollAmount.GetValue().x + halfWidth ) ) {
|
|
clickedRow->SetCursorOnLine( i - clickedRow->GetStart() );
|
|
break;
|
|
}
|
|
}
|
|
if( i > clickedRow->GetEnd() ) {
|
|
clickedRow->SetCursorOnLine( clickedRow->GetLength() );
|
|
}
|
|
}
|
|
|
|
mouseClick.Set( -1.0f, -1.0f );
|
|
}
|
|
|
|
tdhOffset.Zero();
|
|
|
|
sdTextLine* line = lines.Next();
|
|
while( line != NULL ) {
|
|
if( line == currentLine ) {
|
|
tdhOffset.x = tdh.GetWidth( line->GetStart(), currentLine->GetStringIndexForCursor() - 1 );
|
|
break;
|
|
}
|
|
tdhOffset.y += tdh.GetLineHeight();
|
|
line = line->GetNode().Next();
|
|
}
|
|
|
|
sdBounds2D drawRect = parent->GetDrawRect();
|
|
|
|
tdhOffset += drawRect.GetMins() - rect.GetMins();
|
|
|
|
newCursorPos = rect.GetMins() + tdhOffset;
|
|
if( parent->GetUI() != NULL ) {
|
|
cursorDrawTime = parent->GetUI()->GetCurrentTime() + CURSOR_FLASH_TIME;
|
|
}
|
|
drawCursor = true;
|
|
|
|
idVec2 offset = parent->scrollAmount;
|
|
if( newCursorPos.x >= drawRect.GetMaxs().x ) {
|
|
// moved past the right end
|
|
if( ( newCursorPos.x + offset.x ) >= cursorDrawPosition.x ) {
|
|
offset.x = ( drawRect.GetMaxs().x - newCursorPos.x ) - parent->cursor.width;
|
|
}
|
|
} else if( ( newCursorPos.x + offset.x ) <= drawRect.GetMins().x ) {
|
|
// moving past the left side
|
|
offset.x = ( newCursorPos.x + offset.x ) - drawRect.GetMins().x;
|
|
}
|
|
|
|
if( parent->TestFlag( UIEditClass::EF_MULTILINE ) ) {
|
|
if( adjustVScroll ) {
|
|
if( newCursorPos.y + offset.y + parent->cursor.height > rect.GetMaxs().y ) {
|
|
// moved past the bottom
|
|
offset.y -= tdh.GetLineHeight() + ( offset.y + ( newCursorPos.y + parent->cursor.height ) - rect.GetMaxs().y );
|
|
} else if( newCursorPos.y + offset.y <= rect.GetMins().y ) {
|
|
// moving past the top
|
|
offset.y = -( GetCurrentLineIndex() * tdh.GetLineHeight() );
|
|
}
|
|
}
|
|
offset.x = 0.0f;
|
|
} else {
|
|
offset.y = 0.0f;
|
|
}
|
|
|
|
parent->scrollAmount = offset;
|
|
|
|
cursorDrawPosition = newCursorPos + offset;
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::TextChanged
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::TextChanged() {
|
|
textDirty = false;
|
|
|
|
int currentCursor = currentLine->GetStringIndexForCursor() + cursorMove;
|
|
|
|
localText = sdClipboardConverter< StrClass >::ToClipboard( parent->editText.GetValue() );
|
|
|
|
// insert cursor text if required
|
|
const wchar_t* cursorText = parent->GetCursorText();
|
|
|
|
if ( *cursorText != L'\0' ) {
|
|
localText.Insert( cursorText, currentCursor );
|
|
}
|
|
|
|
// update text
|
|
int textLength = localText.Length();
|
|
|
|
if ( parent->password != 0.0f ) {
|
|
localText.Fill( L'*', textLength );
|
|
}
|
|
|
|
ClearLines();
|
|
|
|
sdBounds2D rect = parent->GetDrawRect();
|
|
|
|
parent->ActivateFont( false );
|
|
|
|
tdh.Init( localText.c_str(), textLength, rect, parent->GetDrawTextFlags(), parent->cachedFontHandle, parent->fontSize, &lineBreaks );
|
|
|
|
int currentPos = 0;
|
|
|
|
for( int i = 0; i < lineBreaks.Num(); i++ ) {
|
|
int index = lineBreaks[ i ] - 1;
|
|
sdTextLine* line = new sdTextLine( currentPos, index );
|
|
line->GetNode().AddToEnd( lines );
|
|
currentPos = lineBreaks[ i ];
|
|
if( localText[ currentPos ] == L'\n' ) {
|
|
currentPos++;
|
|
}
|
|
}
|
|
|
|
sdTextLine* line = new sdTextLine( currentPos, textLength );
|
|
line->GetNode().AddToEnd( lines );
|
|
|
|
currentLine = lines.Next();
|
|
currentLine->SetCursorOnLine( 0 );
|
|
|
|
parent->lineHeight.SetReadOnly( false );
|
|
parent->lineHeight = tdh.GetLineHeight();
|
|
parent->lineHeight.SetReadOnly( true );
|
|
|
|
if( parent->TestFlag( UIEditClass::EF_MULTILINE ) ) {
|
|
parent->scrollAmountMax.SetReadOnly( false );
|
|
float amount = ( ( lines.Num() ) * parent->lineHeight ) - parent->cachedClientRect.w;
|
|
if( amount > 0.0f ) {
|
|
parent->scrollAmountMax = amount;
|
|
} else {
|
|
parent->scrollAmountMax = 0.0f;
|
|
}
|
|
|
|
parent->scrollAmountMax.SetReadOnly( true );
|
|
}
|
|
|
|
if( localText.IsEmpty() ) {
|
|
parent->scrollAmount = vec2_zero;
|
|
}
|
|
currentLine = currentLine->AdvanceCursor( currentCursor );
|
|
cursorMove = 0;
|
|
CursorChanged();
|
|
}
|
|
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
bool sdUIEditHelper< UIEditClass, StrClass, CharType >::CaptureChar( const CharType ch ) {
|
|
bool isNewline = ch == '\n';
|
|
if ( isNewline && !parent->TestFlag( UIEditClass::EF_MULTILINE ) ) {
|
|
return false;
|
|
}
|
|
|
|
bool retVal = false;
|
|
unsigned int flags = parent->GetDrawTextFlags();
|
|
|
|
if ( UIEditClass::CharIsPrintable( ch ) || ( isNewline && ( ( flags & DTF_WORDWRAP ) || !( flags & DTF_SINGLELINE ) ) ) ) {
|
|
bool isNumeric = idStr::CharIsNumeric( ch );
|
|
bool isDecimal = ch == '.';
|
|
bool allowInput = true;
|
|
|
|
bool allowDecimal = parent->TestFlag( UIEditClass::EF_ALLOW_DECIMAL );
|
|
bool acceptOnlyNumbers = parent->TestFlag( UIEditClass::EF_INTEGERS_ONLY );
|
|
|
|
if ( acceptOnlyNumbers ) {
|
|
if ( !isDecimal && !isNumeric ) {
|
|
allowInput = false;
|
|
} else if ( isDecimal && !allowDecimal ) {
|
|
allowInput = false;
|
|
}
|
|
}
|
|
|
|
// Can't check for this here as it depends on editText, which is deferred
|
|
/*if ( allowDecimal && isDecimal ) {
|
|
if ( parent->editText.GetValue().Find( static_cast< CharType >( ch ) ) != -1 ) {
|
|
allowInput = false;
|
|
}
|
|
}*/
|
|
|
|
if ( allowInput ) {
|
|
retVal = true;
|
|
}
|
|
} else {
|
|
parent->RunEvent( sdUIEventInfo( UIEditClass::EE_INPUT_FAILED, 0 ) );
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::InsertChar( CharType ch, int& cursorMove ) {
|
|
bool isNewline = ch == '\n';
|
|
if ( isNewline && !parent->TestFlag( UIEditClass::EF_MULTILINE ) ) {
|
|
return;
|
|
}
|
|
|
|
unsigned int flags = parent->GetDrawTextFlags();
|
|
|
|
if ( UIEditClass::CharIsPrintable( ch ) || ( isNewline && ( ( flags & DTF_WORDWRAP ) || !( flags & DTF_SINGLELINE ) ) ) ) {
|
|
bool isNumeric = idStr::CharIsNumeric( ch );
|
|
bool isDecimal = ch == '.';
|
|
bool allowInput = true;
|
|
|
|
bool allowDecimal = parent->TestFlag( UIEditClass::EF_ALLOW_DECIMAL );
|
|
bool acceptOnlyNumbers = parent->TestFlag( UIEditClass::EF_INTEGERS_ONLY );
|
|
|
|
if ( acceptOnlyNumbers ) {
|
|
if ( !isDecimal && !isNumeric ) {
|
|
allowInput = false;
|
|
} else if ( isDecimal && !allowDecimal ) {
|
|
allowInput = false;
|
|
}
|
|
}
|
|
|
|
if ( allowDecimal && isDecimal ) {
|
|
if ( parent->editText.GetValue().Find( static_cast< CharType >( ch ) ) != -1 ) {
|
|
allowInput = false;
|
|
}
|
|
}
|
|
|
|
if ( allowInput ) {
|
|
// FIXME: this is wrong for non english-ish languages
|
|
// don't make a separate undo for an unbroken string of typing
|
|
if ( !lastEventWasCharacter ) {
|
|
SaveUndo();
|
|
}
|
|
|
|
lastEventWasCharacter = true;
|
|
int numErased = 0;
|
|
int selStart;
|
|
int selEnd;
|
|
|
|
GetSelectionRange( selStart, selEnd );
|
|
|
|
if ( SelectionActive() ) {
|
|
numErased = EraseSelection();
|
|
if( selectionStart < currentLine->GetStringIndexForCursor() ) {
|
|
cursorMove += selectionStart - currentLine->GetStringIndexForCursor() + 1;
|
|
} else {
|
|
cursorMove += 1;
|
|
}
|
|
} else {
|
|
cursorMove += 1;
|
|
}
|
|
|
|
UpdateIndexByColorCodes( selStart, selEnd );
|
|
|
|
if ( parent->TestFlag( UIEditClass::EF_UPPERCASE ) ) {
|
|
ch = sdCaseConverter< CharType >::ToUpper( ch );
|
|
}
|
|
|
|
StrClass temp = parent->editText;
|
|
temp.Insert( static_cast< CharType >( ch ), selEnd - numErased );
|
|
parent->editText = temp;
|
|
CancelSelection(); // collapse the selection after the replacement
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::OnGainFocus
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::OnGainFocus() {
|
|
if( parent->GetUI() != NULL ) {
|
|
cursorDrawTime = parent->GetUI()->GetCurrentTime() + CURSOR_FLASH_TIME;
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::InsertText
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::InsertText( const CharType* text ) {
|
|
if ( parent->readOnly ) {
|
|
return;
|
|
}
|
|
|
|
int len = StrClass::Length( text );
|
|
|
|
size_t dataSize = ( len + 1 ) * sizeof( CharType );
|
|
void* data = Mem_Alloc( dataSize );
|
|
::memcpy( data, text, dataSize );
|
|
QueueEvent( sdUIEditEvent::EE_INSERT_TEXT, 0, 0, 0, 0, 0, dataSize, data );
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::DoInsertText
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::DoInsertText( const CharType* text ) {
|
|
int numErased = 0;
|
|
if ( SelectionActive() ) {
|
|
numErased = EraseSelection();
|
|
}
|
|
|
|
int selStart;
|
|
int selEnd;
|
|
GetSelectionRange( selStart, selEnd );
|
|
StrClass temp = parent->editText;
|
|
temp.Insert( text, selEnd - numErased );
|
|
|
|
if ( parent->maxTextLength == 0.0f || temp.LengthWithoutColors() <= parent->maxTextLength ) {
|
|
if ( parent->TestFlag( UIEditClass::EF_UPPERCASE ) ) {
|
|
for ( int i = 0; i < temp.Length(); i++ ) {
|
|
temp[ i ] = sdCaseConverter< CharType >::ToUpper( temp[ i ] );
|
|
}
|
|
}
|
|
SaveUndo();
|
|
parent->editText = temp;
|
|
|
|
CancelSelection();
|
|
cursorMove += StrClass::Length( text );
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::SurroundSelection
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::SurroundSelection( const CharType* prefix, const CharType* suffix ) {
|
|
if ( parent->readOnly ) {
|
|
return;
|
|
}
|
|
int selStart;
|
|
int selEnd;
|
|
GetSelectionRange( selStart, selEnd );
|
|
StrClass temp = parent->editText;
|
|
if ( selStart < 0 ) {
|
|
selStart = 0;
|
|
}
|
|
if ( selEnd < 0 ) {
|
|
selEnd = temp.Length();
|
|
}
|
|
temp.Insert( suffix, selEnd );
|
|
temp.Insert( prefix, selStart );
|
|
|
|
if ( parent->maxTextLength == 0.0f || temp.LengthWithoutColors() <= parent->maxTextLength ) {
|
|
if ( parent->TestFlag( UIEditClass::EF_UPPERCASE ) ) {
|
|
for ( int i = 0; i < temp.Length(); i++ ) {
|
|
temp[ i ] = sdCaseConverter< CharType >::ToUpper( temp[ i ] );
|
|
}
|
|
}
|
|
SaveUndo();
|
|
parent->editText = temp;
|
|
|
|
int len = StrClass::Length( prefix );
|
|
cursorMove += len;
|
|
|
|
if ( selectionStart != -1 ) {
|
|
selectionStart += len;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::SelectAll
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::SelectAll() {
|
|
selectionStart = 0;
|
|
currentLine = currentLine->AdvanceCursor( parent->editText.GetValue().Length() - currentLine->GetStringIndexForCursor() );
|
|
CursorChanged();
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUIEditHelper::GetCurrentLineIndex
|
|
============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
int sdUIEditHelper< UIEditClass, StrClass, CharType >::GetCurrentLineIndex() const {
|
|
sdTextLine* line = lines.Next();
|
|
int index = 0;
|
|
while( line != currentLine ) {
|
|
index++;
|
|
line = line->GetNode().Next();
|
|
}
|
|
return index;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
sdUIEditHelper::FreeEvent
|
|
=================
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::FreeEvent( const sdUIEditEvent* ev ) {
|
|
sdUIEditEvent* event = const_cast< sdUIEditEvent* >( ev );
|
|
event->GetNode().Remove();
|
|
eventAllocator.Free( event );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
sdUIEditHelper::GenerateBlankEvent
|
|
=================
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::QueueEvent( typename sdUIEditEvent::type_e type, int value, int value2, int value3, int value4, int flags, size_t dataSize, void* data ) {
|
|
sdUIEditEvent* ev = eventAllocator.Alloc();
|
|
ev->Init( type, value, value2, value3, value4, flags, dataSize, data );
|
|
ev->GetNode().AddToEnd( eventQueue );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
sdUIEditHelper::GetEvent
|
|
=================
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
const typename sdUIEditHelper< UIEditClass, StrClass, CharType >::sdUIEditEvent* sdUIEditHelper< UIEditClass, StrClass, CharType >::GetEvent() {
|
|
return eventQueue.Next();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdUIEditHelper::RunEventLoop
|
|
===============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::RunEventLoop() {
|
|
while ( true ) {
|
|
const sdUIEditEvent* ev = GetEvent();
|
|
|
|
// if no more events are available
|
|
if ( ev == NULL ) {
|
|
return;
|
|
}
|
|
|
|
ProcessEvent( *ev );
|
|
FreeEvent( ev );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdUIEditHelper::RunEventLoop
|
|
===============
|
|
*/
|
|
template < class UIEditClass, class StrClass, typename CharType >
|
|
void sdUIEditHelper< UIEditClass, StrClass, CharType >::ApplyLayout() {
|
|
RunEventLoop();
|
|
}
|
|
|
|
#endif // ! __GAME_GUIS_USERINTERFACEEDITHELPER_H__
|