1. wxNcPaintEvent for wxMSW
2. wxTextCtrl (single line) cursor movement/basic editing git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8382 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -46,6 +46,7 @@
|
||||
// ============================================================================
|
||||
|
||||
BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
|
||||
EVT_CHAR(OnChar)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
|
||||
@@ -80,7 +81,8 @@ bool wxTextCtrl::Create(wxWindow *parent,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wxCaret *caret = new wxCaret(this, 1, GetCharHeight());
|
||||
// FIXME use renderer
|
||||
wxCaret *caret = new wxCaret(this, 2, GetCharHeight());
|
||||
SetCaret(caret);
|
||||
caret->Show();
|
||||
|
||||
@@ -98,6 +100,9 @@ bool wxTextCtrl::Create(wxWindow *parent,
|
||||
|
||||
void wxTextCtrl::SetValue(const wxString& value)
|
||||
{
|
||||
if ( m_value == value )
|
||||
return;
|
||||
|
||||
m_value = value;
|
||||
|
||||
if ( IsSingleLine() )
|
||||
@@ -108,6 +113,8 @@ void wxTextCtrl::SetValue(const wxString& value)
|
||||
{
|
||||
SetInsertionPoint(0);
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
wxString wxTextCtrl::GetValue() const
|
||||
@@ -120,15 +127,38 @@ void wxTextCtrl::Clear()
|
||||
SetValue(_T(""));
|
||||
}
|
||||
|
||||
void wxTextCtrl::Replace(long from, long to, const wxString& value)
|
||||
void wxTextCtrl::Replace(long from, long to, const wxString& text)
|
||||
{
|
||||
wxFAIL_MSG(_T("not implemented"));
|
||||
wxCHECK_RET( from >= 0 && to >= 0 && from <= to,
|
||||
_T("invalid range in wxTextCtrl::Replace") );
|
||||
|
||||
// replace the part of the text with the new value
|
||||
wxString valueNew(m_value, (size_t)from);
|
||||
valueNew += text;
|
||||
if ( (unsigned long)to < m_value.length() )
|
||||
{
|
||||
valueNew += m_value.c_str() + (size_t)to;
|
||||
}
|
||||
m_value = valueNew;
|
||||
|
||||
// update current position
|
||||
SetInsertionPoint(from + text.length());
|
||||
|
||||
// FIXME shouldn't refresh everything of course
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void wxTextCtrl::Remove(long from, long to)
|
||||
{
|
||||
if ( from > to )
|
||||
{
|
||||
// Replace() only works with correctly ordered arguments, so exchange
|
||||
// them
|
||||
long tmp = from;
|
||||
from = to;
|
||||
to = tmp;
|
||||
}
|
||||
|
||||
Replace(from, to, _T(""));
|
||||
}
|
||||
|
||||
@@ -149,11 +179,27 @@ void wxTextCtrl::AppendText(const wxString& text)
|
||||
|
||||
void wxTextCtrl::SetInsertionPoint(long pos)
|
||||
{
|
||||
HideCaret();
|
||||
wxCHECK_RET( pos >= 0 && pos <= GetLastPosition(),
|
||||
_T("insertion poitn position out of range") );
|
||||
|
||||
m_curPos = pos;
|
||||
if ( pos != m_curPos )
|
||||
{
|
||||
HideCaret();
|
||||
|
||||
ShowCaret();
|
||||
m_curPos = pos;
|
||||
|
||||
if ( IsSingleLine() )
|
||||
{
|
||||
m_curLine = 0;
|
||||
m_curRow = m_curPos;
|
||||
}
|
||||
else // multi line
|
||||
{
|
||||
wxFAIL_MSG(_T("unimplemented for multi line"));
|
||||
}
|
||||
|
||||
ShowCaret();
|
||||
}
|
||||
}
|
||||
|
||||
void wxTextCtrl::SetInsertionPointEnd()
|
||||
@@ -322,6 +368,82 @@ void wxTextCtrl::ShowPosition(long pos)
|
||||
wxFAIL_MSG(_T("not implemented"));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// word stuff
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
TODO: we could have (easy to do) vi-like options for word movement, i.e.
|
||||
distinguish between inlusive/exclusive words and between words and
|
||||
WORDS (in vim sense) and also, finally, make the set of characters
|
||||
which make up a word configurable - currently we use the exclusive
|
||||
WORDS only (coincidentally, this is what Windows edit control does)
|
||||
|
||||
For future references, here is what vim help says:
|
||||
|
||||
A word consists of a sequence of letters, digits and underscores, or
|
||||
a sequence of other non-blank characters, separated with white space
|
||||
(spaces, tabs, <EOL>). This can be changed with the 'iskeyword'
|
||||
option.
|
||||
|
||||
A WORD consists of a sequence of non-blank characters, separated with
|
||||
white space. An empty line is also considered to be a word and a
|
||||
WORD.
|
||||
*/
|
||||
|
||||
static inline bool IsWordChar(wxChar ch)
|
||||
{
|
||||
return !wxIsspace(ch);
|
||||
}
|
||||
|
||||
long wxTextCtrl::GetWordStart() const
|
||||
{
|
||||
if ( m_curPos == -1 || m_curPos == 0 )
|
||||
return 0;
|
||||
|
||||
// start at the previous position
|
||||
const wxChar *p0 = m_value.c_str();
|
||||
const wxChar *p = p0 + m_curPos - 1;
|
||||
|
||||
// find the end of the previous word
|
||||
while ( (p > p0) && !IsWordChar(*p) )
|
||||
p--;
|
||||
|
||||
// now find the beginning of this word
|
||||
while ( (p > p0) && IsWordChar(*p) )
|
||||
p--;
|
||||
|
||||
// we might have gone too far
|
||||
if ( !IsWordChar(*p) )
|
||||
p++;
|
||||
|
||||
return p - p0;
|
||||
}
|
||||
|
||||
long wxTextCtrl::GetWordEnd() const
|
||||
{
|
||||
if ( m_curPos == -1 )
|
||||
return 0;
|
||||
|
||||
// start at the current position
|
||||
const wxChar *p0 = m_value.c_str();
|
||||
const wxChar *p = p0 + m_curPos;
|
||||
|
||||
// find the start of the next word
|
||||
while ( *p && !IsWordChar(*p) )
|
||||
p++;
|
||||
|
||||
// now find the end of it
|
||||
while ( *p && IsWordChar(*p) )
|
||||
p++;
|
||||
|
||||
// and find the start of the next word
|
||||
while ( *p && !IsWordChar(*p) )
|
||||
p++;
|
||||
|
||||
return p - p0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// clipboard stuff
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -381,6 +503,7 @@ wxSize wxTextCtrl::DoGetBestClientSize() const
|
||||
h = hChar;
|
||||
|
||||
w += 2*wChar;
|
||||
h += hChar / 2;
|
||||
|
||||
return wxSize(w, h);
|
||||
}
|
||||
@@ -394,7 +517,7 @@ void wxTextCtrl::DoDraw(wxControlRenderer *renderer)
|
||||
if ( IsSingleLine() )
|
||||
{
|
||||
// just redraw everything
|
||||
renderer->GetDC().DrawText(m_value, 0, 0);
|
||||
renderer->DrawTextLine(m_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -416,7 +539,8 @@ void wxTextCtrl::ShowCaret(bool show)
|
||||
wxCoord x;
|
||||
GetTextExtent(textBeforeCaret, &x, NULL);
|
||||
|
||||
caret->Move(x + 1, 0);
|
||||
// FIXME: use renderer
|
||||
caret->Move(x + 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,11 +554,194 @@ wxString wxTextCtrl::GetInputHandlerType() const
|
||||
return wxINP_HANDLER_TEXTCTRL;
|
||||
}
|
||||
|
||||
bool wxTextCtrl::PerformAction(const wxControlAction& action,
|
||||
bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig,
|
||||
long numArg,
|
||||
const wxString& strArg)
|
||||
{
|
||||
return wxControl::PerformAction(action, numArg, strArg);
|
||||
bool textChanged = FALSE;
|
||||
|
||||
wxString action;
|
||||
bool del = FALSE;
|
||||
if ( actionOrig.StartsWith(wxACTION_TEXT_PREFIX_DEL, &action) )
|
||||
{
|
||||
del = TRUE;
|
||||
}
|
||||
else // not selection nor delete action
|
||||
{
|
||||
action = actionOrig;
|
||||
}
|
||||
|
||||
long newPos = -1;
|
||||
if ( action == wxACTION_TEXT_HOME )
|
||||
{
|
||||
newPos = m_curPos - m_curRow;
|
||||
}
|
||||
else if ( action == wxACTION_TEXT_END )
|
||||
{
|
||||
newPos = m_curPos + GetLineLength(m_curLine) - m_curRow;
|
||||
}
|
||||
else if ( action == wxACTION_TEXT_LEFT )
|
||||
{
|
||||
newPos = m_curPos - 1;
|
||||
}
|
||||
else if ( action == wxACTION_TEXT_WORD_LEFT )
|
||||
{
|
||||
newPos = GetWordStart();
|
||||
}
|
||||
else if ( action == wxACTION_TEXT_RIGHT )
|
||||
{
|
||||
newPos = m_curPos + 1;
|
||||
}
|
||||
else if ( action == wxACTION_TEXT_WORD_RIGHT )
|
||||
{
|
||||
newPos = GetWordEnd();
|
||||
}
|
||||
else if ( action == wxACTION_TEXT_INSERT )
|
||||
{
|
||||
if ( !strArg.empty() )
|
||||
{
|
||||
WriteText(strArg);
|
||||
|
||||
textChanged = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxControl::PerformAction(action, numArg, strArg);
|
||||
}
|
||||
|
||||
if ( newPos != -1 )
|
||||
{
|
||||
// bring the new position into the range
|
||||
if ( newPos < 0 )
|
||||
newPos = 0;
|
||||
|
||||
long posLast = GetLastPosition();
|
||||
if ( newPos > posLast )
|
||||
newPos = posLast;
|
||||
|
||||
if ( del )
|
||||
{
|
||||
// delete everything between current opsition and the new one
|
||||
if ( m_curPos != newPos )
|
||||
{
|
||||
Remove(m_curPos, newPos);
|
||||
|
||||
textChanged = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// just go there
|
||||
SetInsertionPoint(newPos);
|
||||
}
|
||||
}
|
||||
|
||||
if ( textChanged )
|
||||
{
|
||||
wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
|
||||
InitCommandEvent(event);
|
||||
event.SetString(GetValue());
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void wxTextCtrl::OnChar(wxKeyEvent& event)
|
||||
{
|
||||
// only process the key events from "simple keys" here
|
||||
if ( !event.HasModifiers() )
|
||||
{
|
||||
int keycode = event.GetKeyCode();
|
||||
if ( keycode != WXK_DELETE && keycode != WXK_BACK )
|
||||
{
|
||||
PerformAction(wxACTION_TEXT_INSERT, -1, (wxChar)keycode);
|
||||
|
||||
// skip event.Skip() below
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxStdTextCtrlInputHandler
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxStdTextCtrlInputHandler::wxStdTextCtrlInputHandler(wxInputHandler *inphand)
|
||||
: wxStdInputHandler(inphand)
|
||||
{
|
||||
}
|
||||
|
||||
bool wxStdTextCtrlInputHandler::HandleKey(wxControl *control,
|
||||
const wxKeyEvent& event,
|
||||
bool pressed)
|
||||
{
|
||||
if ( !pressed )
|
||||
return FALSE;
|
||||
|
||||
wxControlAction action;
|
||||
wxString str;
|
||||
bool ctrlDown = event.ControlDown();
|
||||
if ( event.ShiftDown() )
|
||||
{
|
||||
action = wxACTION_TEXT_PREFIX_SEL;
|
||||
}
|
||||
|
||||
int keycode = event.GetKeyCode();
|
||||
switch ( keycode )
|
||||
{
|
||||
// cursor movement
|
||||
case WXK_HOME:
|
||||
action << wxACTION_TEXT_HOME;
|
||||
break;
|
||||
|
||||
case WXK_END:
|
||||
action << wxACTION_TEXT_END;
|
||||
break;
|
||||
|
||||
case WXK_LEFT:
|
||||
action << (ctrlDown ? wxACTION_TEXT_WORD_LEFT
|
||||
: wxACTION_TEXT_LEFT);
|
||||
break;
|
||||
|
||||
case WXK_RIGHT:
|
||||
action << (ctrlDown ? wxACTION_TEXT_WORD_RIGHT
|
||||
: wxACTION_TEXT_RIGHT);
|
||||
break;
|
||||
|
||||
// delete
|
||||
case WXK_DELETE:
|
||||
action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_RIGHT;
|
||||
break;
|
||||
|
||||
case WXK_BACK:
|
||||
action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_LEFT;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !!action )
|
||||
{
|
||||
control->PerformAction(action, -1, str);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return wxStdInputHandler::HandleKey(control, event, pressed);
|
||||
}
|
||||
|
||||
bool wxStdTextCtrlInputHandler::HandleMouse(wxControl *control,
|
||||
const wxMouseEvent& event)
|
||||
{
|
||||
return wxStdInputHandler::HandleMouse(control, event);
|
||||
}
|
||||
|
||||
bool wxStdTextCtrlInputHandler::HandleMouseMove(wxControl *control,
|
||||
const wxMouseEvent& event)
|
||||
{
|
||||
return wxStdInputHandler::HandleMouseMove(control, event);
|
||||
}
|
||||
|
||||
#endif // wxUSE_TEXTCTRL
|
||||
|
Reference in New Issue
Block a user