Merge branch 'univ_textctrl_fixtest' of https://github.com/Kvaz1r/wxWidgets

Fix multiple problems in wxUniv wxTextCtrl, allowing it to pass more
unit tests.

See https://github.com/wxWidgets/wxWidgets/pull/2447
This commit is contained in:
Vadim Zeitlin 2021-08-17 23:47:03 +02:00
commit 5d0b3c1129
4 changed files with 93 additions and 51 deletions

View file

@ -36,6 +36,7 @@ class WXDLLIMPEXP_FWD_CORE wxTextCtrlCommandProcessor;
#define wxACTION_TEXT_WORD_RIGHT wxT("wordright")
#define wxACTION_TEXT_PAGE_UP wxT("pageup")
#define wxACTION_TEXT_PAGE_DOWN wxT("pagedown")
#define wxACTION_TEXT_RETURN wxT("return")
// clipboard operations
#define wxACTION_TEXT_COPY wxT("copy")
@ -451,6 +452,8 @@ protected:
bool DoCut();
bool DoPaste();
bool ClickDefaultButtonIfPossible();
private:
// all these methods are for multiline text controls only

View file

@ -96,8 +96,12 @@ void wxDialog::OnOK(wxCommandEvent &WXUNUSED(event))
}
else
{
SetReturnCode(wxID_OK);
Show(false);
// don't change return code from event char if it was set earlier
if (GetReturnCode() == 0)
{
SetReturnCode(wxID_OK);
Show(false);
}
}
}
}

View file

@ -790,10 +790,7 @@ void wxTextCtrl::DoSetValue(const wxString& value, int flags)
Replace(0, GetLastPosition(), value);
if ( IsSingleLine() )
{
SetInsertionPoint(0);
}
SetInsertionPoint(0);
}
else // nothing changed
{
@ -1724,11 +1721,10 @@ wxTextPos wxTextCtrl::XYToPosition(wxTextCoord x, wxTextCoord y) const
}
else // multiline
{
if ( (size_t)y >= GetLineCount() )
{
// this position is below the text
return GetLastPosition();
}
size_t nLineCount = GetLineCount();
if ((size_t)y >= nLineCount)
return -1;
wxTextPos pos = 0;
for ( size_t nLine = 0; nLine < (size_t)y; nLine++ )
@ -1736,14 +1732,12 @@ wxTextPos wxTextCtrl::XYToPosition(wxTextCoord x, wxTextCoord y) const
// +1 is because the positions at the end of this line and of the
// start of the next one are different
pos += GetLines()[nLine].length() + 1;
}
// take into account also the position in line
// out of the line
if ( (size_t)x > GetLines()[y].length() )
{
// don't return position in the next line
x = GetLines()[y].length();
}
return -1;
return pos + x;
}
@ -1770,9 +1764,10 @@ bool wxTextCtrl::PositionToXY(wxTextPos pos,
size_t nLineCount = GetLineCount();
for ( size_t nLine = 0; nLine < nLineCount; nLine++ )
{
// +1 is because the start the start of the next line is one
// +1 is because the start of the next line is one
// position after the end of this one
wxTextPos posNew = posCur + GetLines()[nLine].length() + 1;
if ( posNew > pos )
{
// we've found the line, now just calc the column
@ -2459,7 +2454,7 @@ void wxTextCtrl::UpdateLastVisible()
return;
// use (efficient) HitTestLine to find the last visible character
wxString text = m_value.Mid((size_t)SData().m_colStart /* to the end */);
wxString text = m_value;
wxTextCoord col;
switch ( HitTestLine(text, m_rectText.width, &col) )
{
@ -2884,16 +2879,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line,
dc.GetTextExtent(line, &width, NULL);
if ( x >= width )
{
// clicking beyond the end of line is equivalent to clicking at
// the end of it, so return the last line column
col = line.length();
if ( col )
{
// unless the line is empty and so doesn't have any column at all -
// in this case return 0, what else can we do?
col--;
}
res = wxTE_HT_BEYOND;
}
else if ( x < 0 )
@ -3388,7 +3374,7 @@ void wxTextCtrl::ScrollText(wxTextCoord col)
SData().m_colStart = col;
// after changing m_colStart, recalc the last visible position: we need
// to recalc the last visible position beore scrolling in order to make
// to recalc the last visible position before scrolling in order to make
// it appear exactly at the right edge of the text area after scrolling
UpdateLastVisible();
@ -4671,6 +4657,15 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig,
if ( CanRedo() )
Redo();
}
else if ( action == wxACTION_TEXT_RETURN )
{
// activate default button
if ( !HasFlag(wxTE_PROCESS_ENTER) && !HasFlag(wxTE_MULTILINE) )
{
return ClickDefaultButtonIfPossible();
}
return false;
}
else
{
return wxControl::PerformAction(action, numArg, strArg);
@ -4763,12 +4758,18 @@ void wxTextCtrl::OnChar(wxKeyEvent& event)
#endif
if ( keycode == WXK_RETURN )
{
if ( IsSingleLine() || (GetWindowStyle() & wxTE_PROCESS_ENTER) )
if ( (GetWindowStyle() & wxTE_PROCESS_ENTER) )
{
wxCommandEvent event(wxEVT_TEXT_ENTER, GetId());
InitCommandEvent(event);
event.SetString(GetValue());
GetEventHandler()->ProcessEvent(event);
if( GetEventHandler()->ProcessEvent(event) )
return;
}
if ( IsSingleLine() )
{
ClickDefaultButtonIfPossible();
}
else // interpret <Enter> normally: insert new line
{
@ -4800,6 +4801,23 @@ void wxTextCtrl::OnChar(wxKeyEvent& event)
event.Skip();
}
bool wxTextCtrl::ClickDefaultButtonIfPossible()
{
wxTopLevelWindow* tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
if ( tlw )
{
wxButton* btn = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
if ( btn )
{
wxCommandEvent evt(wxEVT_BUTTON, btn->GetId());
evt.SetEventObject(btn);
btn->Command(evt);
return true;
}
}
return false;
}
/* static */
wxInputHandler *wxTextCtrl::GetStdInputHandler(wxInputHandler *handlerDef)
{
@ -4917,6 +4935,9 @@ bool wxStdTextCtrlInputHandler::HandleKey(wxInputConsumer *consumer,
action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_LEFT;
break;
case WXK_RETURN:
action << wxACTION_TEXT_RETURN;
break;
// something else
default:
// reset the action as it could be already set to one of the
@ -4952,7 +4973,11 @@ bool wxStdTextCtrlInputHandler::HandleKey(wxInputConsumer *consumer,
if ( (action != wxACTION_NONE) && (action != wxACTION_TEXT_PREFIX_SEL) )
{
consumer->PerformAction(action, -1, str);
bool result = consumer->PerformAction(action, -1, str);
if ( !result && action == wxACTION_TEXT_RETURN )
{
return wxStdInputHandler::HandleKey(consumer, event, pressed);
}
// the key down of WXK_UP/DOWN and WXK_PAGEUP/DOWN
// must generate a wxEVT_TEXT event. For the controls

View file

@ -38,6 +38,12 @@
static const int TEXT_HEIGHT = 200;
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
#define wxHAS_2CHAR_NEWLINES 1
#else
#define wxHAS_2CHAR_NEWLINES 0
#endif
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
@ -437,7 +443,7 @@ void TextCtrlTestCase::ProcessEnter()
void TextCtrlTestCase::Url()
{
#if wxUSE_UIACTIONSIMULATOR && defined(__WXMSW__)
#if wxUSE_UIACTIONSIMULATOR && wxHAS_2CHAR_NEWLINES
// For some unfathomable reason, this test consistently fails when run in
// AppVeyor CI environment, even though it passes locally, so skip it
// there.
@ -543,7 +549,11 @@ void TextCtrlTestCase::FontStyle()
m_text->AppendText("Default font size 14");
wxTextAttr attrOut;
m_text->GetStyle(5, attrOut);
if ( !m_text->GetStyle(5, attrOut) )
{
WARN("Retrieving text style not supported, skipping test.");
return;
}
CPPUNIT_ASSERT( attrOut.HasFont() );
@ -686,7 +696,7 @@ void TextCtrlTestCase::DoPositionToCoordsTestWithStyle(long style)
const wxPoint pos0 = m_text->PositionToCoords(0);
if ( pos0 == wxDefaultPosition )
{
#if defined(__WXMSW__) || defined(__WXGTK20__)
#if ( wxHAS_2CHAR_NEWLINES ) || defined(__WXGTK20__)
CPPUNIT_FAIL( "PositionToCoords() unexpectedly failed." );
#endif
return;
@ -789,7 +799,7 @@ void TextCtrlTestCase::DoPositionToXYMultiLine(long style)
delete m_text;
CreateText(style|wxTE_MULTILINE|wxTE_DONTWRAP);
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
const bool isRichEdit = (style & (wxTE_RICH | wxTE_RICH2)) != 0;
#endif
@ -840,7 +850,7 @@ void TextCtrlTestCase::DoPositionToXYMultiLine(long style)
text = wxS("123\nab\nX");
m_text->SetValue(text);
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
// Take into account that every new line mark occupies
// two characters, not one.
const long numChars_msw_2 = 8 + 2;
@ -859,14 +869,14 @@ void TextCtrlTestCase::DoPositionToXYMultiLine(long style)
{ 0, 2 }, { 1, 2 } };
const long &ref_numChars_2 =
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
isRichEdit ? numChars_2 : numChars_msw_2;
#else
numChars_2;
#endif
XYPos *ref_coords_2 =
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
isRichEdit ? coords_2 : coords_2_msw;
#else
coords_2;
@ -888,7 +898,7 @@ void TextCtrlTestCase::DoPositionToXYMultiLine(long style)
text = wxS("\n\n\n");
m_text->SetValue(text);
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
// Take into account that every new line mark occupies
// two characters, not one.
const long numChars_msw_3 = 3 + 3;
@ -909,14 +919,14 @@ void TextCtrlTestCase::DoPositionToXYMultiLine(long style)
{ 0, 3 } };
const long &ref_numChars_3 =
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
isRichEdit ? numChars_3 : numChars_msw_3;
#else
numChars_3;
#endif
XYPos *ref_coords_3 =
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
isRichEdit ? coords_3 : coords_3_msw;
#else
coords_3;
@ -938,7 +948,7 @@ void TextCtrlTestCase::DoPositionToXYMultiLine(long style)
text = wxS("123\na\n\nX\n\n");
m_text->SetValue(text);
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
// Take into account that every new line mark occupies
// two characters, not one.
const long numChars_msw_4 = 10 + 5;
@ -963,14 +973,14 @@ void TextCtrlTestCase::DoPositionToXYMultiLine(long style)
{ 0, 5 } };
const long &ref_numChars_4 =
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
isRichEdit ? numChars_4 : numChars_msw_4;
#else
numChars_4;
#endif
XYPos *ref_coords_4 =
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
isRichEdit ? coords_4 : coords_4_msw;
#else
coords_4;
@ -1011,7 +1021,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style)
delete m_text;
CreateText(style|wxTE_MULTILINE|wxTE_DONTWRAP);
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
const bool isRichEdit = (style & (wxTE_RICH | wxTE_RICH2)) != 0;
#endif
@ -1055,7 +1065,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style)
const long maxLineLength_2 = 4;
const long numLines_2 = 3;
CPPUNIT_ASSERT_EQUAL( numLines_2, m_text->GetNumberOfLines() );
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
// Note: New lines are occupied by two characters.
long pos_2_msw[numLines_2 + 1][maxLineLength_2 + 1] =
{ { 0, 1, 2, 3, -1 }, // New line occupies positions 3, 4
@ -1070,7 +1080,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style)
{ -1, -1, -1, -1, -1 } };
long (&ref_pos_2)[numLines_2 + 1][maxLineLength_2 + 1] =
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
isRichEdit ? pos_2 : pos_2_msw;
#else
pos_2;
@ -1090,7 +1100,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style)
const long maxLineLength_3 = 1;
const long numLines_3 = 4;
CPPUNIT_ASSERT_EQUAL( numLines_3, m_text->GetNumberOfLines() );
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
// Note: New lines are occupied by two characters.
long pos_3_msw[numLines_3 + 1][maxLineLength_3 + 1] =
{ { 0, -1 }, // New line occupies positions 0, 1
@ -1107,7 +1117,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style)
{ -1, -1 } };
long (&ref_pos_3)[numLines_3 + 1][maxLineLength_3 + 1] =
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
isRichEdit ? pos_3 : pos_3_msw;
#else
pos_3;
@ -1127,7 +1137,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style)
const long maxLineLength_4 = 4;
const long numLines_4 = 6;
CPPUNIT_ASSERT_EQUAL( numLines_4, m_text->GetNumberOfLines() );
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
// Note: New lines are occupied by two characters.
long pos_4_msw[numLines_4 + 1][maxLineLength_4 + 1] =
{ { 0, 1, 2, 3, -1 }, // New line occupies positions 3, 4
@ -1148,7 +1158,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style)
{ -1, -1, -1, -1, -1 } };
long (&ref_pos_4)[numLines_4 + 1][maxLineLength_4 + 1] =
#if defined(__WXMSW__)
#if wxHAS_2CHAR_NEWLINES
isRichEdit ? pos_4 : pos_4_msw;
#else
pos_4;