diff --git a/include/wx/univ/textctrl.h b/include/wx/univ/textctrl.h index 3a15244a8b..7b59237332 100644 --- a/include/wx/univ/textctrl.h +++ b/include/wx/univ/textctrl.h @@ -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 diff --git a/src/univ/dialog.cpp b/src/univ/dialog.cpp index 8de1a92a5d..fae198adbb 100644 --- a/src/univ/dialog.cpp +++ b/src/univ/dialog.cpp @@ -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); + } } } } diff --git a/src/univ/textctrl.cpp b/src/univ/textctrl.cpp index d9fc2e365e..0d66222326 100644 --- a/src/univ/textctrl.cpp +++ b/src/univ/textctrl.cpp @@ -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 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 diff --git a/tests/controls/textctrltest.cpp b/tests/controls/textctrltest.cpp index 9d17f13892..7098df48f8 100644 --- a/tests/controls/textctrltest.cpp +++ b/tests/controls/textctrltest.cpp @@ -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;