Files
wxWidgets/src/x11/textctrl.cpp
Vadim Zeitlin ce7fe42e84 Provide shorter synonyms for wxEVT_XXX constants.
Use the same short names as are used by the event table macros for the event
type constants themselves. This makes them much more comfortable to use, e.g.
Bind(wxEVT_BUTTON) compared to Bind(wxEVT_COMMAND_BUTTON_CLICKED).

The old long names are still kept for backwards compatibility and shouldn't be
removed as it doesn't really cost anything to continue providing them, but all
new event types should only use the short versions.

Closes #10661.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@73850 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-04-25 10:11:03 +00:00

2405 lines
61 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/x11/textctrl.cpp
// Purpose:
// Author: Robert Roebling
// Id: $Id$
// Copyright: (c) 1998 Robert Roebling
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#include "wx/textctrl.h"
#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/utils.h"
#include "wx/panel.h"
#include "wx/dcclient.h"
#include "wx/settings.h"
#endif
#include "wx/clipbrd.h"
#include "wx/tokenzr.h"
#include "wx/univ/inphand.h"
#include "wx/univ/renderer.h"
#include "wx/univ/colschem.h"
#include "wx/univ/theme.h"
//-----------------------------------------------------------------------------
// helpers
//-----------------------------------------------------------------------------
wxSourceUndoStep::wxSourceUndoStep( wxSourceUndo type, int y1, int y2, wxTextCtrl *owner )
{
m_type = type;
m_y1 = y1;
m_y2 = y2;
m_owner = owner;
m_cursorX = m_owner->GetCursorX();
m_cursorY = m_owner->GetCursorY();
if (m_type == wxSOURCE_UNDO_LINE)
{
m_text = m_owner->m_lines[m_y1].m_text;
} else
if (m_type == wxSOURCE_UNDO_ENTER)
{
m_text = m_owner->m_lines[m_y1].m_text;
} else
if (m_type == wxSOURCE_UNDO_BACK)
{
for (int i = m_y1; i < m_y2+2; i++)
{
if (i >= (int)m_owner->m_lines.GetCount())
m_lines.Add( wxEmptyString );
else
m_lines.Add( m_owner->m_lines[i].m_text );
}
} else
if (m_type == wxSOURCE_UNDO_DELETE)
{
for (int i = m_y1; i < m_y2+1; i++)
{
m_lines.Add( m_owner->m_lines[i].m_text );
}
} else
if (m_type == wxSOURCE_UNDO_PASTE)
{
m_text = m_owner->m_lines[m_y1].m_text;
}
}
void wxSourceUndoStep::Undo()
{
if (m_type == wxSOURCE_UNDO_LINE)
{
m_owner->m_lines[m_y1].m_text = m_text;
m_owner->MoveCursor( m_cursorX, m_cursorY );
m_owner->RefreshLine( m_y1 );
} else
if (m_type == wxSOURCE_UNDO_ENTER)
{
m_owner->m_lines[m_y1].m_text = m_text;
m_owner->m_lines.RemoveAt( m_y1+1 );
m_owner->MoveCursor( m_cursorX, m_cursorY );
m_owner->RefreshDown( m_y1 );
} else
if (m_type == wxSOURCE_UNDO_BACK)
{
m_owner->m_lines[m_y1].m_text = m_lines[0];
m_owner->m_lines.Insert( new wxSourceLine( m_lines[1] ), m_y1+1 );
m_owner->MyAdjustScrollbars();
m_owner->MoveCursor( m_cursorX, m_cursorY );
m_owner->RefreshDown( m_y1 );
} else
if (m_type == wxSOURCE_UNDO_DELETE)
{
m_owner->m_lines[m_y1].m_text = m_lines[0];
for (int i = 1; i < (int)m_lines.GetCount(); i++)
m_owner->m_lines.Insert( new wxSourceLine( m_lines[i] ), m_y1+i );
m_owner->MyAdjustScrollbars();
m_owner->MoveCursor( m_cursorX, m_cursorY );
m_owner->RefreshDown( m_y1 );
} else
if (m_type == wxSOURCE_UNDO_PASTE)
{
m_owner->m_lines[m_y1].m_text = m_text;
for (int i = 0; i < m_y2-m_y1; i++)
m_owner->m_lines.RemoveAt( m_y1+1 );
m_owner->MyAdjustScrollbars();
m_owner->MoveCursor( m_cursorX, m_cursorY );
m_owner->RefreshDown( m_y1 );
} else
if (m_type == wxSOURCE_UNDO_INSERT_LINE)
{
m_owner->m_lines.RemoveAt( m_y1 );
m_owner->MyAdjustScrollbars();
m_owner->MoveCursor( 0, m_y1 );
m_owner->RefreshDown( m_y1 );
}
}
#include "wx/arrimpl.cpp"
WX_DEFINE_OBJARRAY(wxSourceLineArray);
//-----------------------------------------------------------------------------
// wxTextCtrl
//-----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
EVT_PAINT(wxTextCtrl::OnPaint)
EVT_ERASE_BACKGROUND(wxTextCtrl::OnEraseBackground)
EVT_CHAR(wxTextCtrl::OnChar)
EVT_MOUSE_EVENTS(wxTextCtrl::OnMouse)
EVT_KILL_FOCUS(wxTextCtrl::OnKillFocus)
EVT_SET_FOCUS(wxTextCtrl::OnSetFocus)
EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
END_EVENT_TABLE()
void wxTextCtrl::Init()
{
m_editable = true;
m_modified = false;
m_lang = wxSOURCE_LANG_NONE;
m_capturing = false;
m_cursorX = 0;
m_cursorY = 0;
m_longestLine = 0;
m_bracketX = -1;
m_bracketY = -1;
m_overwrite = false;
m_ignoreInput = false;
ClearSelection();
m_keywordColour = wxColour( 10, 140, 10 );
m_defineColour = *wxRED;
m_variableColour = wxColour( 50, 120, 150 );
m_commentColour = wxColour( 130, 130, 130 );
m_stringColour = wxColour( 10, 140, 10 );
}
wxTextCtrl::wxTextCtrl( wxWindow *parent,
wxWindowID id,
const wxString &value,
const wxPoint &pos,
const wxSize &size,
long style,
const wxValidator& validator,
const wxString &name )
: wxScrollHelper(this)
{
Init();
Create( parent, id, value, pos, size, style, validator, name );
}
wxTextCtrl::~wxTextCtrl()
{
WX_CLEAR_LIST(wxList, m_undos);
}
bool wxTextCtrl::Create( wxWindow *parent,
wxWindowID id,
const wxString &value,
const wxPoint &pos,
const wxSize &size,
long style,
const wxValidator& validator,
const wxString &name )
{
if ((style & wxBORDER_MASK) == 0)
style |= wxBORDER_SUNKEN;
if ((style & wxTE_MULTILINE) != 0)
style |= wxALWAYS_SHOW_SB;
wxTextCtrlBase::Create( parent, id, pos /* wxDefaultPosition */, size,
style | wxVSCROLL | wxHSCROLL);
SetBackgroundColour( *wxWHITE );
SetCursor( wxCursor( wxCURSOR_IBEAM ) );
m_editable = ((m_windowStyle & wxTE_READONLY) == 0);
if (HasFlag(wxTE_PASSWORD))
m_sourceFont = wxFont( 12, wxMODERN, wxNORMAL, wxNORMAL );
else
m_sourceFont = GetFont();
wxClientDC dc(this);
dc.SetFont( m_sourceFont );
m_lineHeight = dc.GetCharHeight();
m_charWidth = dc.GetCharWidth();
SetValue( value );
wxSize size_best( DoGetBestSize() );
wxSize new_size( size );
if (new_size.x == -1)
new_size.x = size_best.x;
if (new_size.y == -1)
new_size.y = size_best.y;
if ((new_size.x != size.x) || (new_size.y != size.y))
SetSize( new_size.x, new_size.y );
// We create an input handler since it might be useful
CreateInputHandler(wxINP_HANDLER_TEXTCTRL);
MyAdjustScrollbars();
return true;
}
//-----------------------------------------------------------------------------
// public methods
//-----------------------------------------------------------------------------
wxString wxTextCtrl::GetValue() const
{
wxString ret;
for (size_t i = 0; i < m_lines.GetCount(); i++)
{
ret += m_lines[i].m_text;
if (i+1 < m_lines.GetCount())
ret += wxT('\n');
}
return ret;
}
void wxTextCtrl::DoSetValue(const wxString& value, int flags)
{
m_modified = false;
wxString oldValue = GetValue();
m_cursorX = 0;
m_cursorY = 0;
ClearSelection();
m_lines.Clear();
m_longestLine = 0;
if (value.empty())
{
m_lines.Add( new wxSourceLine( wxEmptyString ) );
}
else
{
int begin = 0;
int pos = 0;
for (;;)
{
pos = value.find( wxT('\n'), begin );
if (pos < 0)
{
wxSourceLine *sl = new wxSourceLine( value.Mid( begin, value.Len()-begin ) );
m_lines.Add( sl );
// if (sl->m_text.Len() > m_longestLine)
// m_longestLine = sl->m_text.Len();
int ww = 0;
GetTextExtent( sl->m_text, &ww, NULL, NULL, NULL );
ww /= m_charWidth;
if (ww > m_longestLine)
m_longestLine = ww;
break;
}
else
{
wxSourceLine *sl = new wxSourceLine( value.Mid( begin, pos-begin ) );
m_lines.Add( sl );
// if (sl->m_text.Len() > m_longestLine)
// m_longestLine = sl->m_text.Len();
int ww = 0;
GetTextExtent( sl->m_text, &ww, NULL, NULL, NULL );
ww /= m_charWidth;
if (ww > m_longestLine)
m_longestLine = ww;
begin = pos+1;
}
}
}
// Don't need to refresh if the value hasn't changed
if ((GetWindowStyle() & wxTE_MULTILINE) == 0)
{
if (value == oldValue)
return;
}
MyAdjustScrollbars();
Refresh();
if ( flags & SetValue_SendEvent )
SendTextUpdatedEvent();
}
int wxTextCtrl::GetLineLength(long lineNo) const
{
if (lineNo >= (long)m_lines.GetCount())
return 0;
return m_lines[lineNo].m_text.Len();
}
wxString wxTextCtrl::GetLineText(long lineNo) const
{
if (lineNo >= (long)m_lines.GetCount())
return wxEmptyString;
return m_lines[lineNo].m_text;
}
int wxTextCtrl::GetNumberOfLines() const
{
return m_lines.GetCount();
}
bool wxTextCtrl::IsModified() const
{
return m_modified;
}
bool wxTextCtrl::IsEditable() const
{
return m_editable;
}
void wxTextCtrl::GetSelection(long* from, long* to) const
{
if (m_selStartX == -1 || m_selStartY == -1 ||
m_selEndX == -1 || m_selEndY == -1)
{
*from = GetInsertionPoint();
*to = GetInsertionPoint();
}
else
{
*from = XYToPosition(m_selStartX, m_selStartY);
*to = XYToPosition(m_selEndX, m_selEndY);
}
}
void wxTextCtrl::Clear()
{
m_modified = true;
m_cursorX = 0;
m_cursorY = 0;
ClearSelection();
m_lines.Clear();
m_lines.Add( new wxSourceLine( wxEmptyString ) );
SetScrollbars( m_charWidth, m_lineHeight, 0, 0, 0, 0 );
Refresh();
WX_CLEAR_LIST(wxList, m_undos);
}
void wxTextCtrl::Replace(long from, long to, const wxString& value)
{
}
void wxTextCtrl::Remove(long from, long to)
{
}
void wxTextCtrl::DiscardEdits()
{
ClearSelection();
Refresh();
}
void wxTextCtrl::SetMaxLength(unsigned long len)
{
}
int wxTextCtrl::PosToPixel( int line, int pos )
{
// TODO add support for Tabs
if (line >= (int)m_lines.GetCount()) return 0;
if (pos < 0) return 0;
wxString text = m_lines[line].m_text;
if (text.empty()) return 0;
if (pos < (int)text.Len())
text.Remove( pos, text.Len()-pos );
int w = 0;
GetTextExtent( text, &w, NULL, NULL, NULL );
return w;
}
int wxTextCtrl::PixelToPos( int line, int pixel )
{
if (pixel < 2) return 0;
if (line >= (int)m_lines.GetCount()) return 0;
wxString text = m_lines[line].m_text;
int w = 0;
int res = text.Len();
while (res > 0)
{
GetTextExtent( text, &w, NULL, NULL, NULL );
if (w < pixel)
return res;
res--;
text.Remove( res,1 );
}
return 0;
}
void wxTextCtrl::SetLanguage( wxSourceLanguage lang )
{
m_lang = lang;
m_keywords.Clear();
}
void wxTextCtrl::WriteText(const wxString& text2)
{
if (text2.empty()) return;
m_modified = true;
wxString text( text2 );
wxArrayString lines;
int pos;
while ( (pos = text.Find('\n')) != -1 )
{
lines.Add( text.Left( pos ) );
text.Remove( 0, pos+1 );
}
lines.Add( text );
int count = (int)lines.GetCount();
wxString tmp1( m_lines[m_cursorY].m_text );
wxString tmp2( tmp1 );
int len = (int)tmp1.Len();
if (len < m_cursorX)
{
wxString tmp;
for (int i = 0; i < m_cursorX-len; i++)
tmp.Append( ' ' );
m_lines[m_cursorY].m_text.Append( tmp );
tmp1.Append( tmp );
tmp2.Append( tmp );
}
tmp1.Remove( m_cursorX );
tmp2.Remove( 0, m_cursorX );
tmp1.Append( lines[0] );
if (count == 1)
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
tmp1.Append( tmp2 );
m_lines[m_cursorY].m_text = tmp1;
RefreshLine( m_cursorY );
}
else
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_PASTE, m_cursorY, m_cursorY+count-1, this ) );
m_lines[m_cursorY].m_text = tmp1;
int i;
for (i = 1; i < count; i++)
m_lines.Insert( new wxSourceLine( lines[i] ), m_cursorY+i );
m_lines[m_cursorY+i-1].m_text.Append( tmp2 );
MyAdjustScrollbars();
RefreshDown( m_cursorY );
}
}
void wxTextCtrl::AppendText(const wxString& text2)
{
if (text2.empty()) return;
m_modified = true;
wxString text( text2 );
wxArrayString lines;
int pos;
while ( (pos = text.Find('\n')) != -1 )
{
lines.Add( text.Left( pos ) );
text.Remove( 0, pos+1 );
}
lines.Add( text );
int count = (int)lines.GetCount();
size_t y = m_lines.GetCount()-1;
wxString tmp( m_lines[y].m_text );
tmp.Append( lines[0] );
if (count == 1)
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, y, y, this ) );
m_lines[y].m_text = tmp;
RefreshLine( y );
}
else
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_PASTE, y, y+count-1, this ) );
m_lines[y].m_text = tmp;
int i;
for (i = 1; i < count; i++)
m_lines.Insert( new wxSourceLine( lines[i] ), y+i );
MyAdjustScrollbars();
RefreshDown( y );
}
}
bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
{
return false;
}
long wxTextCtrl::XYToPosition(long x, long y) const
{
long ret = 0;
for (size_t i = 0; i < m_lines.GetCount(); i++)
{
if (i < (size_t)y)
{
// Add one for the end-of-line character
ret += m_lines[i].m_text.Len() + 1;
continue;
}
if ((size_t)x < (m_lines[i].m_text.Len()+1))
return (ret + x);
else
return (ret + m_lines[i].m_text.Len() + 1);
}
return ret;
}
bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
{
if (m_lines.GetCount() == 0)
{
if (x) *x = 0;
if (y) *y = 0;
return (pos == 0);
}
long xx = 0;
long yy = 0;
for (size_t i = 0; i < m_lines.GetCount(); i++)
{
//pos -= m_lines[i].m_text.Len();
//if (pos <= 0)
// Add one for the end-of-line character. (In Windows,
// there are _two_ positions for each end of line.)
if (pos <= ((int)m_lines[i].m_text.Len()))
{
xx = pos;
if (x) *x = xx;
if (y) *y = yy;
return true;
}
pos -= (m_lines[i].m_text.Len() + 1);
yy++;
}
// Last pos
//xx = m_lines[ m_lines.GetCount()-1 ].m_text.Len();
xx = pos;
if (x) *x = xx;
if (y) *y = yy;
return false;
}
void wxTextCtrl::ShowPosition(long pos)
{
}
void wxTextCtrl::Copy()
{
if (!HasSelection()) return;
wxString sel;
int selStartY = m_selStartY;
int selEndY = m_selEndY;
int selStartX = m_selStartX;
int selEndX = m_selEndX;
if ((selStartY > selEndY) ||
((selStartY == selEndY) && (selStartX > selEndX)))
{
int tmp = selStartX;
selStartX = selEndX;
selEndX = tmp;
tmp = selStartY;
selStartY = selEndY;
selEndY = tmp;
}
if (selStartY == selEndY)
{
sel = m_lines[selStartY].m_text;
if (selStartX >= (int)sel.Len()) return;
if (selEndX > (int)sel.Len())
selEndX = sel.Len();
sel.Remove( selEndX, sel.Len()-selEndX );
sel.Remove( 0, selStartX );
}
else
{
wxString tmp( m_lines[selStartY].m_text );
if (selStartX < (int)tmp.Len())
{
tmp.Remove( 0, selStartX );
sel = tmp;
sel.Append( wxT("\n") );
}
for (int i = selStartY+1; i < selEndY; i++)
{
sel.Append( m_lines[i].m_text );
sel.Append( wxT("\n") );
}
tmp = m_lines[selEndY].m_text;
if (selEndX > (int)tmp.Len())
selEndX = tmp.Len();
if (selEndX > 0)
{
tmp.Remove( selEndX, tmp.Len()-selEndX );
sel.Append( tmp );
}
}
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData( new wxTextDataObject( sel ) );
wxTheClipboard->Close();
}
}
void wxTextCtrl::Cut()
{
Copy();
Delete();
}
void wxTextCtrl::Paste()
{
Delete();
if (!wxTheClipboard->Open()) return;
if (!wxTheClipboard->IsSupported( wxDF_TEXT ))
{
wxTheClipboard->Close();
return;
}
wxTextDataObject data;
bool ret = wxTheClipboard->GetData( data );
wxTheClipboard->Close();
if (!ret) return;
m_modified = true;
wxString text( data.GetText() );
wxArrayString lines;
int pos;
while ( (pos = text.Find('\n')) != -1 )
{
lines.Add( text.Left( pos ) );
text.Remove( 0, pos+1 );
}
lines.Add( text );
int count = (int)lines.GetCount();
wxString tmp1( m_lines[m_cursorY].m_text );
wxString tmp2( tmp1 );
int len = (int)tmp1.Len();
if (len < m_cursorX)
{
wxString tmp;
for (int i = 0; i < m_cursorX-len; i++)
tmp.Append( ' ' );
m_lines[m_cursorY].m_text.Append( tmp );
tmp1.Append( tmp );
tmp2.Append( tmp );
}
tmp1.Remove( m_cursorX );
tmp2.Remove( 0, m_cursorX );
tmp1.Append( lines[0] );
if (count == 1)
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
tmp1.Append( tmp2 );
m_lines[m_cursorY].m_text = tmp1;
RefreshLine( m_cursorY );
}
else
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_PASTE, m_cursorY, m_cursorY+count-1, this ) );
m_lines[m_cursorY].m_text = tmp1;
int i;
for (i = 1; i < count; i++)
m_lines.Insert( new wxSourceLine( lines[i] ), m_cursorY+i );
m_lines[m_cursorY+i-1].m_text.Append( tmp2 );
MyAdjustScrollbars();
RefreshDown( m_cursorY );
}
}
void wxTextCtrl::Undo()
{
if (m_undos.GetCount() == 0) return;
wxList::compatibility_iterator node = m_undos.Item( m_undos.GetCount()-1 );
wxSourceUndoStep *undo = (wxSourceUndoStep*) node->GetData();
undo->Undo();
delete undo;
m_undos.Erase( node );
m_modified = true;
}
void wxTextCtrl::SetInsertionPoint(long pos)
{
ClearSelection();
long x, y;
PositionToXY(pos, & x, & y);
m_cursorX = x;
m_cursorY = y;
// TODO: scroll to this position if necessary
Refresh();
}
void wxTextCtrl::SetInsertionPointEnd()
{
SetInsertionPoint(GetLastPosition());
}
long wxTextCtrl::GetInsertionPoint() const
{
return XYToPosition( m_cursorX, m_cursorY );
}
wxTextPos wxTextCtrl::GetLastPosition() const
{
size_t lineCount = m_lines.GetCount() - 1;
// It's the length of the line, not the length - 1,
// because there's a position after the last character.
return XYToPosition( m_lines[lineCount].m_text.Len(), lineCount );
}
void wxTextCtrl::SetSelection(long from, long to)
{
}
void wxTextCtrl::SetEditable(bool editable)
{
m_editable = editable;
}
bool wxTextCtrl::Enable( bool enable )
{
return false;
}
bool wxTextCtrl::SetFont(const wxFont& font)
{
wxTextCtrlBase::SetFont( font );
m_sourceFont = font;
wxClientDC dc(this);
dc.SetFont( m_sourceFont );
m_lineHeight = dc.GetCharHeight();
m_charWidth = dc.GetCharWidth();
// TODO: recalc longest lines
MyAdjustScrollbars();
return true;
}
bool wxTextCtrl::SetForegroundColour(const wxColour& colour)
{
return wxWindow::SetForegroundColour( colour );
}
bool wxTextCtrl::SetBackgroundColour(const wxColour& colour)
{
return wxWindow::SetBackgroundColour( colour );
}
//-----------------------------------------------------------------------------
// private code and handlers
//-----------------------------------------------------------------------------
void wxTextCtrl::SearchForBrackets()
{
int oldBracketY = m_bracketY;
int oldBracketX = m_bracketX;
if (m_cursorY < 0 || m_cursorY >= (int)m_lines.GetCount()) return;
wxString current = m_lines[m_cursorY].m_text;
// reverse search first
char bracket = ' ';
if (m_cursorX > 0)
bracket = current[(size_t) (m_cursorX-1)];
if (bracket == ')' || bracket == ']' || bracket == '}')
{
char antibracket = '(';
if (bracket == ']') antibracket = '[';
if (bracket == '}') antibracket = '{';
int count = 1;
int endY = m_cursorY-60;
if (endY < 0) endY = 0;
for (int y = m_cursorY; y >= endY; y--)
{
current = m_lines[y].m_text;
if (y == m_cursorY)
current.erase(m_cursorX-1,current.Len()-m_cursorX+1);
for (int n = current.Len()-1; n >= 0; n--)
{
// ignore chars
if (current[(size_t) (n)] == '\'')
{
for (int m = n-1; m >= 0; m--)
{
if (current[(size_t) (m)] == '\'')
{
if (m == 0 || current[(size_t) (m-1)] != '\\')
break;
}
n = m-1;
}
continue;
}
// ignore strings
if (current[(size_t) (n)] == '\"')
{
for (int m = n-1; m >= 0; m--)
{
if (current[(size_t) (m)] == '\"')
{
if (m == 0 || current[(size_t) (m-1)] != '\\')
break;
}
n = m-1;
}
continue;
}
if (current[(size_t) (n)] == antibracket)
{
count--;
if (count == 0)
{
m_bracketY = y;
m_bracketX = n;
if (oldBracketY != m_bracketY && oldBracketY != -1)
RefreshLine( oldBracketY );
if (m_bracketY != oldBracketY || m_bracketX != oldBracketX)
RefreshLine( m_bracketY );
return;
}
}
else if (current[(size_t) (n)] == bracket)
{
count++;
}
}
}
}
// then forward
bracket = ' ';
if ((int)current.Len() > m_cursorX)
bracket = current[(size_t) (m_cursorX)];
if (bracket == '(' || bracket == '[' || bracket == '{')
{
char antibracket = ')';
if (bracket == '[') antibracket = ']';
if (bracket == '{') antibracket = '}';
int count = 1;
int endY = m_cursorY+60;
if (endY > (int)(m_lines.GetCount()-1)) endY = m_lines.GetCount()-1;
for (int y = m_cursorY; y <= endY; y++)
{
current = m_lines[y].m_text;
int start = 0;
if (y == m_cursorY)
start = m_cursorX+1;
for (int n = start; n < (int)current.Len(); n++)
{
// ignore chars
if (current[(size_t) (n)] == '\'')
{
for (int m = n+1; m < (int)current.Len(); m++)
{
if (current[(size_t) (m)] == '\'')
{
if (m == 0 || (current[(size_t) (m-1)] != '\\') || (m >= 2 && current[(size_t) (m-2)] == '\\'))
break;
}
n = m+1;
}
continue;
}
// ignore strings
if (current[(size_t) (n)] == '\"')
{
for (int m = n+1; m < (int)current.Len(); m++)
{
if (current[(size_t) (m)] == '\"')
{
if (m == 0 || (current[(size_t) (m-1)] != '\\') || (m >= 2 && current[(size_t) (m-2)] == '\\'))
break;
}
n = m+1;
}
continue;
}
if (current[(size_t) (n)] == antibracket)
{
count--;
if (count == 0)
{
m_bracketY = y;
m_bracketX = n;
if (oldBracketY != m_bracketY && oldBracketY != -1)
RefreshLine( oldBracketY );
if (m_bracketY != oldBracketY || m_bracketX != oldBracketX)
RefreshLine( m_bracketY );
return;
}
}
else if (current[(size_t) (n)] == bracket)
{
count++;
}
}
}
}
if (oldBracketY != -1)
{
m_bracketY = -1;
RefreshLine( oldBracketY );
}
}
void wxTextCtrl::Delete()
{
if (!HasSelection()) return;
m_modified = true;
int selStartY = m_selStartY;
int selEndY = m_selEndY;
int selStartX = m_selStartX;
int selEndX = m_selEndX;
if ((selStartY > selEndY) ||
((selStartY == selEndY) && (selStartX > selEndX)))
{
int tmp = selStartX;
selStartX = selEndX;
selEndX = tmp;
tmp = selStartY;
selStartY = selEndY;
selEndY = tmp;
}
int len = (int)m_lines[selStartY].m_text.Len();
if (selStartY == selEndY)
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, selStartY, selStartY, this ) );
wxString tmp( m_lines[selStartY].m_text );
if (selStartX < len)
{
if (selEndX > len)
selEndX = len;
tmp.Remove( selStartX, selEndX-selStartX );
m_lines[selStartY].m_text = tmp;
}
ClearSelection();
m_cursorX = selStartX;
RefreshLine( selStartY );
}
else
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_DELETE, selStartY, selEndY, this ) );
if (selStartX < len)
m_lines[selStartY].m_text.Remove( selStartX );
for (int i = 0; i < selEndY-selStartY-1; i++)
m_lines.RemoveAt( selStartY+1 );
if (selEndX < (int)m_lines[selStartY+1].m_text.Len())
m_lines[selStartY+1].m_text.Remove( 0, selEndX );
else
m_lines[selStartY+1].m_text.Remove( 0 );
m_lines[selStartY].m_text.Append( m_lines[selStartY+1].m_text );
m_lines.RemoveAt( selStartY+1 );
ClearSelection();
MoveCursor( selStartX, selStartY );
MyAdjustScrollbars();
RefreshDown( selStartY );
}
}
void wxTextCtrl::DeleteLine()
{
if (HasSelection()) return;
if (m_cursorY < 0 || m_cursorY >= (int)m_lines.GetCount()-1) return; // TODO
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_DELETE, m_cursorY, m_cursorY+1, this ) );
m_lines.RemoveAt( m_cursorY );
m_cursorX = 0;
if (m_cursorY >= (int)m_lines.GetCount()) m_cursorY--;
MyAdjustScrollbars();
RefreshDown( m_cursorY );
}
void wxTextCtrl::DoChar( char c )
{
m_modified = true;
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
wxString tmp( m_lines[m_cursorY].m_text );
tmp.Trim();
if (m_cursorX >= (int)tmp.Len())
{
int len = tmp.Len();
for (int i = 0; i < m_cursorX - len; i++)
tmp.Append( ' ' );
tmp.Append( c );
}
else
{
if (m_overwrite)
tmp.SetChar( m_cursorX, c );
else
tmp.insert( m_cursorX, 1, c );
}
m_lines[m_cursorY].m_text = tmp;
// if (tmp.Len() > m_longestLine)
// {
// m_longestLine = tmp.Len();
// MyAdjustScrollbars();
// }
int ww = 0;
GetTextExtent( tmp, &ww, NULL, NULL, NULL );
ww /= m_charWidth;
if (ww > m_longestLine)
{
m_longestLine = ww;
MyAdjustScrollbars();
}
m_cursorX++;
int y = m_cursorY*m_lineHeight;
// int x = (m_cursorX-1)*m_charWidth;
int x = PosToPixel( m_cursorY, m_cursorX-1 );
CalcScrolledPosition( x, y, &x, &y );
wxRect rect( x+2, y+2, 10000, m_lineHeight );
Refresh( true, &rect );
// refresh whole line for syntax colour highlighting
rect.x = 0;
Refresh( false, &rect );
int size_x = 0;
int size_y = 0;
GetClientSize( &size_x, &size_y );
size_x /= m_charWidth;
int view_x = 0;
int view_y = 0;
GetViewStart( &view_x, &view_y );
//int xx = m_cursorX;
int xx = PosToPixel( m_cursorY, m_cursorX ) / m_charWidth;
if (xx < view_x)
Scroll( xx, -1 );
else if (xx > view_x+size_x-1)
Scroll( xx-size_x+1, -1 );
}
void wxTextCtrl::DoBack()
{
m_modified = true;
if (m_cursorX == 0)
{
if (m_cursorY == 0) return;
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_BACK, m_cursorY-1, m_cursorY, this ) );
wxString tmp1( m_lines[m_cursorY-1].m_text );
tmp1.Trim();
wxString tmp2( m_lines[m_cursorY].m_text );
tmp2.Trim();
m_cursorX = tmp1.Len();
m_cursorY--;
tmp1.Append( tmp2 );
m_lines[m_cursorY].m_text = tmp1;
m_lines.RemoveAt( m_cursorY+1 );
MyAdjustScrollbars();
RefreshDown( m_cursorY-1 );
}
else
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
if (m_cursorX <= (int)m_lines[m_cursorY].m_text.Len())
m_lines[m_cursorY].m_text.Remove( m_cursorX-1, 1 );
m_cursorX--;
int y = m_cursorY*m_lineHeight;
// int x = m_cursorX*m_charWidth;
int x = PosToPixel( m_cursorY, m_cursorX );
CalcScrolledPosition( x, y, &x, &y );
wxRect rect( x+2, y+2, 10000, m_lineHeight );
Refresh( true, &rect );
// refresh whole line for syntax colour highlighting
rect.x = 0;
Refresh( false, &rect );
}
}
void wxTextCtrl::DoDelete()
{
m_modified = true;
wxString tmp( m_lines[m_cursorY].m_text );
tmp.Trim();
int len = (int)tmp.Len();
if (m_cursorX >= len)
{
if (m_cursorY == (int)m_lines.GetCount()-1) return;
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_DELETE, m_cursorY, m_cursorY+1, this ) );
for (int i = 0; i < (m_cursorX-len); i++)
tmp += ' ';
tmp += m_lines[m_cursorY+1].m_text;
m_lines[m_cursorY] = tmp;
m_lines.RemoveAt( m_cursorY+1 );
MyAdjustScrollbars();
RefreshDown( m_cursorY );
}
else
{
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
tmp.Remove( m_cursorX, 1 );
m_lines[m_cursorY].m_text = tmp;
int y = m_cursorY*m_lineHeight;
// int x = m_cursorX*m_charWidth;
int x = PosToPixel( m_cursorY, m_cursorX );
CalcScrolledPosition( x, y, &x, &y );
wxRect rect( x+2, y+2, 10000, m_lineHeight );
Refresh( true, &rect );
// refresh whole line for syntax colour highlighting
rect.x = 0;
Refresh( false, &rect );
}
}
void wxTextCtrl::DoReturn()
{
m_modified = true;
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_ENTER, m_cursorY, m_cursorY, this ) );
wxString tmp( m_lines[m_cursorY].m_text );
size_t indent = tmp.find_first_not_of( ' ' );
if (indent == wxSTRING_MAXLEN) indent = 0;
tmp.Trim();
if (m_cursorX >= (int)tmp.Len())
{
int cursorX = indent;
int cursorY = m_cursorY + 1;
wxString new_tmp;
for (size_t i = 0; i < indent; i++) new_tmp.Append( ' ' );
m_lines.Insert( new wxSourceLine( new_tmp ), cursorY );
MyAdjustScrollbars();
MoveCursor( cursorX, cursorY );
RefreshDown( m_cursorY );
}
else
{
wxString tmp1( tmp );
tmp1.Remove( m_cursorX, tmp.Len()-m_cursorX );
m_lines[m_cursorY].m_text = tmp1;
wxString tmp2( tmp );
tmp2.Remove( 0, m_cursorX );
int cursorX = indent;
int cursorY = m_cursorY + 1;
wxString new_tmp;
for (size_t i = 0; i < indent; i++) new_tmp.Append( ' ' );
new_tmp.Append( tmp2 );
m_lines.Insert( new wxSourceLine( new_tmp ), cursorY );
MyAdjustScrollbars();
MoveCursor( cursorX, cursorY );
RefreshDown( m_cursorY-1 );
}
}
void wxTextCtrl::DoDClick()
{
wxString line( m_lines[ m_cursorY ].m_text );
if (m_cursorX >= (int)line.Len()) return;
int p = m_cursorX;
char ch = line[(size_t) (p)];
if (((ch >= 'a') && (ch <= 'z')) ||
((ch >= 'A') && (ch <= 'Z')) ||
((ch >= '0') && (ch <= '9')) ||
(ch == '_'))
{
m_selStartY = m_cursorY;
m_selEndY = m_cursorY;
if (p > 0)
{
ch = line[(size_t) (p-1)];
while (((ch >= 'a') && (ch <= 'z')) ||
((ch >= 'A') && (ch <= 'Z')) ||
((ch >= '0') && (ch <= '9')) ||
(ch == '_'))
{
p--;
if (p == 0) break;
ch = line[(size_t) (p-1)];
}
}
m_selStartX = p;
p = m_cursorX;
if (p < (int)line.Len())
{
ch = line[(size_t) (p)];
while (((ch >= 'a') && (ch <= 'z')) ||
((ch >= 'A') && (ch <= 'Z')) ||
((ch >= '0') && (ch <= '9')) ||
(ch == '_'))
{
if (p >= (int)line.Len()) break;
p++;
ch = line[(size_t) (p)];
}
}
m_selEndX = p;
RefreshLine( m_cursorY );
}
}
wxString wxTextCtrl::GetNextToken( wxString &line, size_t &pos )
{
wxString ret;
size_t len = line.Len();
for (size_t p = pos; p < len; p++)
{
if ((m_lang == wxSOURCE_LANG_PYTHON) || (m_lang == wxSOURCE_LANG_PERL))
{
if (line[p] == '#')
{
for (size_t q = p; q < len; q++)
ret.Append( line[q] );
pos = p;
return ret;
}
}
else
{
if ((line[p] == '/') && (p+1 < len) && (line[(size_t) (p+1)] == '/'))
{
for (size_t q = p; q < len; q++)
ret.Append( line[q] );
pos = p;
return ret;
}
}
if (line[p] == '"')
{
ret.Append( line[p] );
for (size_t q = p+1; q < len; q++)
{
ret.Append( line[q] );
if ((line[q] == '"') && ((line[(size_t) (q-1)] != '\\') || (q >= 2 && line[(size_t) (q-2)] == '\\')))
break;
}
pos = p;
return ret;
}
if (line[p] == '\'')
{
ret.Append( line[p] );
for (size_t q = p+1; q < len; q++)
{
ret.Append( line[q] );
if ((line[q] == '\'') && ((line[(size_t) (q-1)] != '\\') || (q >= 2 && line[(size_t) (q-2)] == '\\')))
break;
}
pos = p;
return ret;
}
if (((line[p] >= 'a') && (line[p] <= 'z')) ||
((line[p] >= 'A') && (line[p] <= 'Z')) ||
(line[p] == '_') ||
(line[p] == '#'))
{
ret.Append( line[p] );
for (size_t q = p+1; q < len; q++)
{
if (((line[q] >= 'a') && (line[q] <= 'z')) ||
((line[q] >= 'A') && (line[q] <= 'Z')) ||
((line[q] >= '0') && (line[q] <= '9')) ||
(line[q] == '_'))
{
ret.Append( line[q] );
continue;
}
else
{
pos = p;
return ret;
}
}
pos = p;
return ret;
}
}
return ret;
}
void wxTextCtrl::OnEraseBackground( wxEraseEvent &event )
{
event.Skip();
}
void wxTextCtrl::DrawLinePart( wxDC &dc, int x, int y, const wxString &toDraw, const wxString &origin, const wxColour &colour )
{
size_t pos = 0;
size_t len = origin.Len();
dc.SetTextForeground( colour );
while (pos < len)
{
while (toDraw[pos] == wxT(' '))
{
pos++;
if (pos == len) return;
}
size_t start = pos;
wxString current;
current += toDraw[pos];
pos++;
while ( (toDraw[pos] == origin[pos]) && (pos < len))
{
current += toDraw[pos];
pos++;
}
int xx = 0;
wxString tmp = origin.Left( start );
GetTextExtent( tmp, &xx, NULL, NULL, NULL );
xx += x;
int yy = y;
dc.DrawText( current, xx, yy );
}
}
void wxTextCtrl::DrawLine( wxDC &dc, int x, int y, const wxString &line2, int lineNum )
{
int selStartY = m_selStartY;
int selEndY = m_selEndY;
int selStartX = m_selStartX;
int selEndX = m_selEndX;
if ((selStartY > selEndY) ||
((selStartY == selEndY) && (selStartX > selEndX)))
{
int tmp = selStartX;
selStartX = selEndX;
selEndX = tmp;
tmp = selStartY;
selStartY = selEndY;
selEndY = tmp;
}
wxString line( line2 );
if (HasFlag(wxTE_PASSWORD))
{
size_t len = line.Len();
line = wxString( wxT('*'), len );
}
wxString keyword( ' ', line.Len() );
wxString define( ' ', line.Len() );
wxString variable( ' ', line.Len() );
wxString comment( ' ', line.Len() );
wxString my_string( ' ', line.Len() );
wxString selection( ' ', line.Len() );
if (m_lang != wxSOURCE_LANG_NONE)
{
if (lineNum == m_bracketY)
{
wxString red( ' ', line.Len() );
if (m_bracketX < (int)line.Len())
{
red.SetChar( m_bracketX, line[(size_t) (m_bracketX)] );
line.SetChar( m_bracketX, ' ' );
dc.SetTextForeground( *wxRED );
dc.DrawText( red, x, y );
dc.SetTextForeground( *wxBLACK );
}
}
size_t pos = 0;
wxString token( GetNextToken( line, pos ) );
while ( !token.empty() )
{
if (m_keywords.Index( token ) != wxNOT_FOUND)
{
size_t end_pos = pos + token.Len();
for (size_t i = pos; i < end_pos; i++)
{
keyword[i] = line[i];
line[i] = ' ';
}
} else
if (m_defines.Index( token ) != wxNOT_FOUND)
{
size_t end_pos = pos + token.Len();
for (size_t i = pos; i < end_pos; i++)
{
define[i] = line[i];
line[i] = ' ';
}
} else
if ((m_variables.Index( token ) != wxNOT_FOUND) ||
((token.Len() > 2) && (token[(size_t) (0)] == 'w') && (token[(size_t) (1)] == 'x')))
{
size_t end_pos = pos + token.Len();
for (size_t i = pos; i < end_pos; i++)
{
variable[i] = line[i];
line[i] = ' ';
}
} else
if ((token.Len() >= 2) && (token[(size_t) (0)] == '/') && (token[(size_t) (1)] == '/') && (m_lang == wxSOURCE_LANG_CPP))
{
size_t end_pos = pos + token.Len();
for (size_t i = pos; i < end_pos; i++)
{
comment[i] = line[i];
line[i] = ' ';
}
} else
if ((token[(size_t) (0)] == '#') &&
((m_lang == wxSOURCE_LANG_PYTHON) || (m_lang == wxSOURCE_LANG_PERL)))
{
size_t end_pos = pos + token.Len();
for (size_t i = pos; i < end_pos; i++)
{
comment[i] = line[i];
line[i] = ' ';
}
} else
if ((token[(size_t) (0)] == '"') || (token[(size_t) (0)] == '\''))
{
size_t end_pos = pos + token.Len();
for (size_t i = pos; i < end_pos; i++)
{
my_string[i] = line[i];
line[i] = ' ';
}
}
pos += token.Len();
token = GetNextToken( line, pos );
}
}
if ((lineNum < selStartY) || (lineNum > selEndY))
{
DrawLinePart( dc, x, y, line, line2, *wxBLACK );
DrawLinePart( dc, x, y, selection, line2, *wxWHITE );
DrawLinePart( dc, x, y, keyword, line2, m_keywordColour );
DrawLinePart( dc, x, y, define, line2, m_defineColour );
DrawLinePart( dc, x, y, variable, line2, m_variableColour );
DrawLinePart( dc, x, y, comment, line2, m_commentColour );
DrawLinePart( dc, x, y, my_string, line2, m_stringColour );
return;
}
if (selStartY == selEndY)
{
// int xx = selStartX*m_charWidth;
int xx = PosToPixel( lineNum, selStartX );
// int ww = (selEndX-selStartX)*m_charWidth;
int ww = PosToPixel( lineNum, selEndX ) - xx;
dc.DrawRectangle( xx+2, lineNum*m_lineHeight+2, ww, m_lineHeight );
for (size_t i = (size_t)selStartX; i < (size_t)selEndX; i++)
{
selection[i] = line[i];
line[i] = ' ';
}
} else
if ((lineNum > selStartY) && (lineNum < selEndY))
{
dc.DrawRectangle( 0+2, lineNum*m_lineHeight+2, 10000, m_lineHeight );
for (size_t i = 0; i < line.Len(); i++)
{
selection[i] = line[i];
line[i] = ' ';
}
} else
if (lineNum == selStartY)
{
// int xx = selStartX*m_charWidth;
int xx = PosToPixel( lineNum, selStartX );
dc.DrawRectangle( xx+2, lineNum*m_lineHeight+2, 10000, m_lineHeight );
for (size_t i = (size_t)selStartX; i < line.Len(); i++)
{
selection[i] = line[i];
line[i] = ' ';
}
} else
if (lineNum == selEndY)
{
// int ww = selEndX*m_charWidth;
int ww = PosToPixel( lineNum, selEndX );
dc.DrawRectangle( 0+2, lineNum*m_lineHeight+2, ww, m_lineHeight );
for (size_t i = 0; i < (size_t)selEndX; i++)
{
selection[i] = line[i];
line[i] = ' ';
}
}
DrawLinePart( dc, x, y, line, line2, *wxBLACK );
DrawLinePart( dc, x, y, selection, line2, *wxWHITE );
DrawLinePart( dc, x, y, keyword, line2, m_keywordColour );
DrawLinePart( dc, x, y, define, line2, m_defineColour );
DrawLinePart( dc, x, y, variable, line2, m_variableColour );
DrawLinePart( dc, x, y, comment, line2, m_commentColour );
DrawLinePart( dc, x, y, my_string, line2, m_stringColour );
}
void wxTextCtrl::OnPaint( wxPaintEvent &event )
{
wxPaintDC dc(this);
if (m_lines.GetCount() == 0) return;
PrepareDC( dc );
dc.SetFont( m_sourceFont );
int scroll_y = 0;
GetViewStart( NULL, &scroll_y );
// We have a inner border of two pixels
// around the text, so scroll units do
// not correspond to lines.
if (scroll_y > 0) scroll_y--;
int size_x = 0;
int size_y = 0;
GetClientSize( &size_x, &size_y );
dc.SetPen( *wxTRANSPARENT_PEN );
dc.SetBrush( wxBrush( wxTHEME_COLOUR(HIGHLIGHT), wxSOLID ) );
int upper = wxMin( (int)m_lines.GetCount(), scroll_y+(size_y/m_lineHeight)+2 );
for (int i = scroll_y; i < upper; i++)
{
int x = 0+2;
int y = i*m_lineHeight+2;
int w = 10000;
int h = m_lineHeight;
CalcScrolledPosition( x,y,&x,&y );
if (IsExposed(x,y,w,h))
DrawLine( dc, 0+2, i*m_lineHeight+2, m_lines[i].m_text, i );
}
if (m_editable && (FindFocus() == this))
{
///dc.SetBrush( *wxRED_BRUSH );
dc.SetBrush( *wxBLACK_BRUSH );
// int xx = m_cursorX*m_charWidth;
int xx = PosToPixel( m_cursorY, m_cursorX );
dc.DrawRectangle( xx+2, m_cursorY*m_lineHeight+2, 2, m_lineHeight );
}
}
void wxTextCtrl::OnMouse( wxMouseEvent &event )
{
if (m_lines.GetCount() == 0) return;
#if 0 // there is no middle button on iPAQs
if (event.MiddleDown())
{
Paste( true );
return;
}
#endif
if (event.LeftDClick())
{
DoDClick();
return;
}
if (event.LeftDown())
{
m_capturing = true;
CaptureMouse();
}
if (event.LeftUp())
{
m_capturing = false;
ReleaseMouse();
}
if (event.LeftDown() ||
(event.LeftIsDown() && m_capturing))
{
int x = event.GetX();
int y = event.GetY();
CalcUnscrolledPosition( x, y, &x, &y );
y /= m_lineHeight;
// x /= m_charWidth;
x = PixelToPos( y, x );
MoveCursor(
wxMin( 1000, wxMax( 0, x ) ),
wxMin( (int)m_lines.GetCount()-1, wxMax( 0, y ) ),
event.ShiftDown() || !event.LeftDown() );
}
}
void wxTextCtrl::OnChar( wxKeyEvent &event )
{
if (m_lines.GetCount() == 0) return;
if (!m_editable) return;
int size_x = 0;
int size_y = 0;
GetClientSize( &size_x, &size_y );
size_x /= m_charWidth;
size_y /= m_lineHeight;
size_y--;
if (event.ShiftDown())
{
switch (event.GetKeyCode())
{
case '4': event.m_keyCode = WXK_LEFT; break;
case '8': event.m_keyCode = WXK_UP; break;
case '6': event.m_keyCode = WXK_RIGHT; break;
case '2': event.m_keyCode = WXK_DOWN; break;
case '9': event.m_keyCode = WXK_PAGEUP; break;
case '3': event.m_keyCode = WXK_PAGEDOWN; break;
case '7': event.m_keyCode = WXK_HOME; break;
case '1': event.m_keyCode = WXK_END; break;
case '0': event.m_keyCode = WXK_INSERT; break;
}
}
switch (event.GetKeyCode())
{
case WXK_UP:
{
if (m_ignoreInput) return;
if (m_cursorY > 0)
MoveCursor( m_cursorX, m_cursorY-1, event.ShiftDown() );
m_ignoreInput = true;
return;
}
case WXK_DOWN:
{
if (m_ignoreInput) return;
if (m_cursorY < (int)(m_lines.GetCount()-1))
MoveCursor( m_cursorX, m_cursorY+1, event.ShiftDown() );
m_ignoreInput = true;
return;
}
case WXK_LEFT:
{
if (m_ignoreInput) return;
if (m_cursorX > 0)
{
MoveCursor( m_cursorX-1, m_cursorY, event.ShiftDown() );
}
else
{
if (m_cursorY > 0)
MoveCursor( m_lines[m_cursorY-1].m_text.Len(), m_cursorY-1, event.ShiftDown() );
}
m_ignoreInput = true;
return;
}
case WXK_RIGHT:
{
if (m_ignoreInput) return;
if (m_cursorX < 1000)
MoveCursor( m_cursorX+1, m_cursorY, event.ShiftDown() );
m_ignoreInput = true;
return;
}
case WXK_HOME:
{
if (event.ControlDown())
MoveCursor( 0, 0, event.ShiftDown() );
else
MoveCursor( 0, m_cursorY, event.ShiftDown() );
return;
}
case WXK_END:
{
if (event.ControlDown())
MoveCursor( 0, m_lines.GetCount()-1, event.ShiftDown() );
else
MoveCursor( m_lines[m_cursorY].m_text.Len(), m_cursorY, event.ShiftDown() );
return;
}
case WXK_NEXT:
{
if (m_ignoreInput) return;
MoveCursor( m_cursorX, wxMin( (int)(m_lines.GetCount()-1), m_cursorY+size_y ), event.ShiftDown() );
m_ignoreInput = true;
return;
}
case WXK_PAGEUP:
{
if (m_ignoreInput) return;
MoveCursor( m_cursorX, wxMax( 0, m_cursorY-size_y ), event.ShiftDown() );
m_ignoreInput = true;
return;
}
case WXK_INSERT:
{
if (event.ShiftDown())
Paste();
else if (event.ControlDown())
Copy();
else
m_overwrite = !m_overwrite;
return;
}
case WXK_RETURN:
{
if (m_windowStyle & wxTE_PROCESS_ENTER)
{
wxCommandEvent event(wxEVT_TEXT_ENTER, m_windowId);
event.SetEventObject(this);
event.SetString(GetValue());
if (HandleWindowEvent(event)) return;
}
if (IsSingleLine())
{
event.Skip();
return;
}
if (HasSelection())
Delete();
DoReturn();
return;
}
case WXK_TAB:
{
if (HasSelection())
Delete();
bool save_overwrite = m_overwrite;
m_overwrite = false;
int i = 4-(m_cursorX % 4);
if (i == 0) i = 4;
for (int c = 0; c < i; c++)
DoChar( ' ' );
m_overwrite = save_overwrite;
return;
}
case WXK_BACK:
{
if (HasSelection())
Delete();
else
DoBack();
return;
}
case WXK_DELETE:
{
if (HasSelection())
Delete();
else
DoDelete();
return;
}
default:
{
if ( (event.GetKeyCode() >= 'a') &&
(event.GetKeyCode() <= 'z') &&
(event.AltDown()) )
{
// Alt-F etc.
event.Skip();
return;
}
if ( (event.GetKeyCode() >= 32) &&
(event.GetKeyCode() <= 255) &&
!(event.ControlDown() && !event.AltDown()) ) // filters out Ctrl-X but leaves Alt-Gr
{
if (HasSelection())
Delete();
DoChar( (char) event.GetKeyCode() );
return;
}
}
}
event.Skip();
}
void wxTextCtrl::OnInternalIdle()
{
wxControl::OnInternalIdle();
m_ignoreInput = false;
if (m_lang != wxSOURCE_LANG_NONE)
SearchForBrackets();
}
void wxTextCtrl::Indent()
{
int startY = m_cursorY;
int endY = m_cursorY;
if (HasSelection())
{
startY = m_selStartY;
endY = m_selEndY;
if (endY < startY)
{
int tmp = startY;
startY = endY;
endY = tmp;
}
}
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, startY, endY, this ) );
for (int i = startY; i <= endY; i++)
{
m_lines[i].m_text.insert( 0u, wxT(" ") );
RefreshLine( i );
}
}
void wxTextCtrl::Unindent()
{
int startY = m_cursorY;
int endY = m_cursorY;
if (HasSelection())
{
startY = m_selStartY;
endY = m_selEndY;
if (endY < startY)
{
int tmp = startY;
startY = endY;
endY = tmp;
}
}
m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, startY, endY, this ) );
for (int i = startY; i <= endY; i++)
{
for (int n = 0; n < 4; n++)
{
if (m_lines[i].m_text[0u] == wxT(' '))
m_lines[i].m_text.erase(0u,1u);
}
RefreshLine( i );
}
}
bool wxTextCtrl::HasSelection()
{
return ((m_selStartY != m_selEndY) || (m_selStartX != m_selEndX));
}
void wxTextCtrl::ClearSelection()
{
m_selStartX = -1;
m_selStartY = -1;
m_selEndX = -1;
m_selEndY = -1;
}
void wxTextCtrl::RefreshLine( int n )
{
int y = n*m_lineHeight;
int x = 0;
CalcScrolledPosition( x, y, &x, &y );
wxRect rect( 0+2, y+2, 10000, m_lineHeight );
Refresh( true, &rect );
}
void wxTextCtrl::RefreshDown( int n )
{
int size_x = 0;
int size_y = 0;
GetClientSize( &size_x, &size_y );
int view_x = 0;
int view_y = 0;
GetViewStart( &view_x, &view_y );
if (n < view_y)
{
Refresh();
}
else
{
int y = n*m_lineHeight;
int x = 0;
CalcScrolledPosition( x, y, &x, &y );
wxRect rect( 0+2, y+2, 10000, size_y );
Refresh( true, &rect );
}
}
void wxTextCtrl::MoveCursor( int new_x, int new_y, bool shift, bool centre )
{
if (!m_editable) return;
// if (IsSingleLine() || (m_lang == wxSOURCE_LANG_NONE))
{
if (new_x > (int) (m_lines[new_y].m_text.Len()))
new_x = m_lines[new_y].m_text.Len();
}
if ((new_x == m_cursorX) && (new_y == m_cursorY)) return;
bool no_cursor_refresh = false;
bool has_selection = HasSelection();
if (shift)
{
int x,y,w,h;
bool erase_background = true;
if (!has_selection)
{
m_selStartX = m_cursorX;
m_selStartY = m_cursorY;
x = 0;
w = 10000;
if (new_y > m_selStartY)
{
y = m_selStartY*m_lineHeight;
h = (new_y-m_selStartY+1)*m_lineHeight;
}
else if (new_y == m_selStartY)
{
x = PosToPixel( new_y, m_selStartX );
w = PosToPixel( new_y, new_x ) - x;
if (w < 0)
{
x += w;
w = -w + 2; // +2 for the cursor
}
y = m_selStartY*m_lineHeight;
h = m_lineHeight;
}
else
{
y = new_y*m_lineHeight;
h = (-new_y+m_selStartY+1)*m_lineHeight;
}
no_cursor_refresh = true;
m_cursorX = new_x;
m_cursorY = new_y;
}
else
{
if (new_y == m_selEndY)
{
y = new_y *m_lineHeight;
h = m_lineHeight;
if (m_selEndX > new_x)
{
// x = new_x*m_charWidth;
x = PosToPixel( new_y, new_x );
// w = (m_selEndX-new_x)*m_charWidth;
w = PosToPixel( new_y, m_selEndX ) - x;
}
else
{
// x = m_selEndX*m_charWidth;
x = PosToPixel( new_y, m_selEndX );
// w = (-m_selEndX+new_x)*m_charWidth;
w = PosToPixel( new_y, new_x ) - x;
}
}
else
{
x = 0;
w = 10000;
if (new_y > m_selEndY)
{
y = m_selEndY*m_lineHeight;
h = (new_y-m_selEndY+1) * m_lineHeight;
erase_background = ((m_selEndY < m_selStartY) ||
((m_selEndY == m_selStartY) && (m_selEndX < m_selStartX)));
}
else
{
y = new_y*m_lineHeight;
h = (-new_y+m_selEndY+1) * m_lineHeight;
erase_background = ((m_selEndY > m_selStartY) ||
((m_selEndY == m_selStartY) && (m_selEndX > m_selStartX)));
}
no_cursor_refresh = true;
m_cursorX = new_x;
m_cursorY = new_y;
}
}
m_selEndX = new_x;
m_selEndY = new_y;
CalcScrolledPosition( x, y, &x, &y );
wxRect rect( x+2, y+2, w, h );
Refresh( erase_background, &rect );
}
else
{
if (has_selection)
{
int ry1 = m_selEndY;
int ry2 = m_selStartY;
m_selEndX = -1;
m_selEndY = -1;
m_selStartX = -1;
m_selStartY = -1;
if (ry1 > ry2)
{
int tmp = ry2;
ry2 = ry1;
ry1 = tmp;
}
int x = 0;
int y = ry1*m_lineHeight;
CalcScrolledPosition( x, y, &x, &y );
wxRect rect( 0, y+2, 10000, (ry2-ry1+1)*m_lineHeight );
Refresh( true, &rect );
}
}
/*
printf( "startx %d starty %d endx %d endy %d\n",
m_selStartX, m_selStartY, m_selEndX, m_selEndY );
printf( "has %d\n", (int)HasSelection() );
*/
if (!no_cursor_refresh)
{
// int x = m_cursorX*m_charWidth;
int x = PosToPixel( m_cursorY, m_cursorX );
int y = m_cursorY*m_lineHeight;
CalcScrolledPosition( x, y, &x, &y );
wxRect rect( x+2, y+2, 4, m_lineHeight+2 );
m_cursorX = new_x;
m_cursorY = new_y;
Refresh( true, &rect );
if (FindFocus() == this)
{
wxClientDC dc(this);
PrepareDC( dc );
dc.SetPen( *wxTRANSPARENT_PEN );
//dc.SetBrush( *wxRED_BRUSH );
dc.SetBrush( *wxBLACK_BRUSH );
// int xx = m_cursorX*m_charWidth;
int xx = PosToPixel( m_cursorY, m_cursorX );
dc.DrawRectangle( xx+2, m_cursorY*m_lineHeight+2, 2, m_lineHeight );
}
}
int size_x = 0;
int size_y = 0;
GetClientSize( &size_x, &size_y );
size_x /= m_charWidth;
size_y /= m_lineHeight;
int view_x = 0;
int view_y = 0;
GetViewStart( &view_x, &view_y );
if (centre)
{
int sy = m_cursorY - (size_y/2);
if (sy < 0) sy = 0;
Scroll( -1, sy );
}
else
{
if (m_cursorY < view_y)
Scroll( -1, m_cursorY );
else if (m_cursorY > view_y+size_y-1)
Scroll( -1, m_cursorY-size_y+1 );
}
//int xx = m_cursorX;
int xx = PosToPixel( m_cursorY, m_cursorX ) / m_charWidth;
if (xx < view_x)
Scroll( xx, -1 );
else if (xx > view_x+size_x-1)
Scroll( xx-size_x+1, -1 );
}
void wxTextCtrl::MyAdjustScrollbars()
{
if (IsSingleLine())
return;
int y_range = m_lines.GetCount();
int height = 0;
GetClientSize( NULL, &height );
height -= 4;
if (height >= (int)m_lines.GetCount() *m_lineHeight)
y_range = 0;
int view_x = 0;
int view_y = 0;
GetViewStart( &view_x, &view_y );
SetScrollbars( m_charWidth, m_lineHeight, m_longestLine+2, y_range, view_x, view_y );
}
//-----------------------------------------------------------------------------
// clipboard handlers
//-----------------------------------------------------------------------------
void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
{
Cut();
}
void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
{
Copy();
}
void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
{
Paste();
}
void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
{
Undo();
}
void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
{
Redo();
}
void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
{
event.Enable( CanCut() );
}
void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
{
event.Enable( CanCopy() );
}
void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
{
event.Enable( CanPaste() );
}
void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
{
event.Enable( CanUndo() );
}
void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
{
event.Enable( CanRedo() );
}
wxSize wxTextCtrl::DoGetBestSize() const
{
if (IsSingleLine())
{
wxSize ret(80, m_lineHeight + 4);
if (HasFlag(wxBORDER_SUNKEN) || HasFlag(wxBORDER_RAISED))
ret.y += 4;
if (HasFlag(wxBORDER_SIMPLE))
ret.y += 2;
return ret;
}
else
{
return wxSize(80, 60);
}
}
void wxTextCtrl::OnSetFocus( wxFocusEvent& event )
{
// To hide or show caret, as appropriate
Refresh();
}
void wxTextCtrl::OnKillFocus( wxFocusEvent& event )
{
// To hide or show caret, as appropriate
Refresh();
}
// ----------------------------------------------------------------------------
// text control scrolling
// ----------------------------------------------------------------------------
bool wxTextCtrl::ScrollLines(int lines)
{
wxFAIL_MSG( "wxTextCtrl::ScrollLines not implemented");
return false;
}
bool wxTextCtrl::ScrollPages(int pages)
{
wxFAIL_MSG( "wxTextCtrl::ScrollPages not implemented");
return false;
}