X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/11db7d81d1f7d2faecac39b05960a5f5cbd15bc6..7848088476db284a94f19eeb24411b45d676ac46:/src/msw/textctrl.cpp?ds=inline diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 9730fe9992..f7c7cb3ada 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -125,14 +125,14 @@ wxBEGIN_FLAGS( wxTextCtrlStyle ) wxFLAGS_MEMBER(wxDOUBLE_BORDER) wxFLAGS_MEMBER(wxRAISED_BORDER) wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxNO_BORDER) + wxFLAGS_MEMBER(wxBORDER) // standard window styles wxFLAGS_MEMBER(wxTAB_TRAVERSAL) wxFLAGS_MEMBER(wxCLIP_CHILDREN) wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) wxFLAGS_MEMBER(wxVSCROLL) wxFLAGS_MEMBER(wxHSCROLL) @@ -199,9 +199,6 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo) EVT_UPDATE_UI(wxID_CLEAR, wxTextCtrl::OnUpdateDelete) EVT_UPDATE_UI(wxID_SELECTALL, wxTextCtrl::OnUpdateSelectAll) -#ifdef __WIN16__ - EVT_ERASE_BACKGROUND(wxTextCtrl::OnEraseBackground) -#endif EVT_SET_FOCUS(wxTextCtrl::OnSetFocus) END_EVENT_TABLE() @@ -534,24 +531,39 @@ wxString wxTextCtrl::GetRange(long from, long to) const // we must use EM_STREAMOUT if we don't want to lose all characters // not representable in the current character set (EM_GETTEXTRANGE // simply replaces them with question marks...) - // - // as EM_STREAMOUT only works for the entire controls contents (or - // just the selection but it's probably a bad idea to play games - // with selection here...), we can't use it unless we're called - // from GetValue(), i.e. we want to retrieve all text - if ( GetRichVersion() > 1 && (from == 0 && to >= len) ) + if ( GetRichVersion() > 1 ) { + // we must have some encoding, otherwise any 8bit chars in the + // control are simply *lost* (replaced by '?') + wxFontEncoding encoding = wxFONTENCODING_SYSTEM; + wxFont font = m_defaultStyle.GetFont(); if ( !font.Ok() ) font = GetFont(); if ( font.Ok() ) { - wxFontEncoding encoding = font.GetEncoding(); - if ( encoding != wxFONTENCODING_SYSTEM ) - { - str = StreamOut(encoding); - } + encoding = font.GetEncoding(); + } + + if ( encoding == wxFONTENCODING_SYSTEM ) + { + encoding = wxLocale::GetSystemEncoding(); + } + + if ( encoding == wxFONTENCODING_SYSTEM ) + { + encoding = wxFONTENCODING_ISO8859_1; + } + + str = StreamOut(encoding); + + if ( !str.empty() ) + { + // we have to manually extract the required part, luckily + // this is easy in this case as EOL characters in str are + // just LFs because we remove CRs in wxRichEditStreamOut + str = str.Mid(from, to - from); } } @@ -622,6 +634,9 @@ void wxTextCtrl::SetValue(const wxString& value) if ( (value.length() > 0x400) || (value != GetValue()) ) { DoWriteText(value, FALSE /* not selection only */); + + // for compatibility, don't move the cursor when doing SetValue() + SetInsertionPoint(0); } else // same text { @@ -634,9 +649,6 @@ void wxTextCtrl::SetValue(const wxString& value) // mark the control as being not dirty - we changed its text, not the // user DiscardEdits(); - - // for compatibility, don't move the cursor when doing SetValue() - SetInsertionPoint(0); } #if wxUSE_RICHEDIT && (!wxUSE_UNICODE || wxUSE_UNICODE_MSLU) @@ -665,24 +677,37 @@ wxRichEditStreamIn(DWORD dwCookie, BYTE *buf, LONG cb, LONG *pcb) return 0; } +// helper struct used to pass parameters from wxTextCtrl to wxRichEditStreamOut +struct wxStreamOutData +{ + wchar_t *wpc; + size_t len; +}; + DWORD CALLBACK -wxRichEditStreamOut(DWORD dwCookie, BYTE *buf, LONG cb, LONG *pcb) +wxRichEditStreamOut(DWORD_PTR dwCookie, BYTE *buf, LONG cb, LONG *pcb) { *pcb = 0; - wchar_t ** const ppws = (wchar_t **)dwCookie; + wxStreamOutData *data = (wxStreamOutData *)dwCookie; const wchar_t *wbuf = (const wchar_t *)buf; - wchar_t *wpc = *ppws; - while ( cb && *wpc ) + wchar_t *wpc = data->wpc; + while ( cb ) { - *wpc++ = *wbuf++; + wchar_t wch = *wbuf++; + + // turn "\r\n" into "\n" on the fly + if ( wch != L'\r' ) + *wpc++ = wch; + else + data->len--; cb -= sizeof(wchar_t); (*pcb) += sizeof(wchar_t); } - *ppws = wpc; + data->wpc = wpc; return 0; } @@ -767,9 +792,13 @@ wxTextCtrl::StreamOut(wxFontEncoding encoding, bool selectionOnly) const wchar_t *wpc = wchBuf; #endif + wxStreamOutData data; + data.wpc = wpc; + data.len = len; + EDITSTREAM eds; wxZeroMemory(eds); - eds.dwCookie = (DWORD)&wpc; + eds.dwCookie = (DWORD)&data; eds.pfnCallback = wxRichEditStreamOut; ::SendMessage @@ -786,13 +815,17 @@ wxTextCtrl::StreamOut(wxFontEncoding encoding, bool selectionOnly) const } else // streamed out ok { - // now convert to the given encoding (this is a lossful conversion but - // what else can we do) + // NUL-terminate the string because its length could have been + // decreased by wxRichEditStreamOut + *(wchBuf.data() + data.len) = L'\0'; + + // now convert to the given encoding (this is a possibly lossful + // conversion but what else can we do) wxCSConv conv(encoding); - size_t lenNeeded = conv.WC2MB(NULL, wchBuf, len); - if ( lenNeeded ) + size_t lenNeeded = conv.WC2MB(NULL, wchBuf, 0); + if ( lenNeeded++ ) { - conv.WC2MB(wxStringBuffer(out, lenNeeded), wchBuf, len); + conv.WC2MB(wxStringBuffer(out, lenNeeded), wchBuf, lenNeeded); } } @@ -1158,7 +1191,6 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret) { HWND hWnd = GetHwnd(); -#ifdef __WIN32__ #if wxUSE_RICHEDIT if ( IsRich() ) { @@ -1214,10 +1246,23 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret) } #endif // wxUSE_RICHEDIT } -#else // Win16 - // WPARAM is 0: selection is scrolled into view - SendMessage(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)MAKELONG(from, to)); -#endif // Win32/16 +} + +// ---------------------------------------------------------------------------- +// Working with files +// ---------------------------------------------------------------------------- + +bool wxTextCtrl::LoadFile(const wxString& file) +{ + if ( wxTextCtrlBase::LoadFile(file) ) + { + // update the size limit if needed + AdjustSpaceLimit(); + + return TRUE; + } + + return FALSE; } // ---------------------------------------------------------------------------- @@ -1229,13 +1274,7 @@ void wxTextCtrl::Replace(long from, long to, const wxString& value) // Set selection and remove it DoSetSelection(from, to, FALSE /* don't scroll caret into view */); - SendMessage(GetHwnd(), EM_REPLACESEL, -#ifdef __WIN32__ - TRUE, -#else - FALSE, -#endif - (LPARAM)value.c_str()); + DoWriteText(value, TRUE /* selection only */); } void wxTextCtrl::Remove(long from, long to) @@ -1243,25 +1282,16 @@ void wxTextCtrl::Remove(long from, long to) Replace(from, to, wxEmptyString); } -bool wxTextCtrl::LoadFile(const wxString& file) +bool wxTextCtrl::IsModified() const { - if ( wxTextCtrlBase::LoadFile(file) ) - { - // update the size limit if needed - AdjustSpaceLimit(); - - return TRUE; - } - - return FALSE; + return SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0; } -bool wxTextCtrl::IsModified() const +void wxTextCtrl::MarkDirty() { - return SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0; + SendMessage(GetHwnd(), EM_SETMODIFY, TRUE, 0L); } -// Makes 'unmodified' void wxTextCtrl::DiscardEdits() { SendMessage(GetHwnd(), EM_SETMODIFY, FALSE, 0L); @@ -1272,6 +1302,10 @@ int wxTextCtrl::GetNumberOfLines() const return (int)SendMessage(GetHwnd(), EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0); } +// ---------------------------------------------------------------------------- +// Positions <-> coords +// ---------------------------------------------------------------------------- + long wxTextCtrl::XYToPosition(long x, long y) const { // This gets the char index for the _beginning_ of this line @@ -1319,6 +1353,99 @@ bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const return TRUE; } +wxTextCtrlHitTestResult +wxTextCtrl::HitTest(const wxPoint& pt, wxTextCoord *col, wxTextCoord *row) const +{ + // first get the position from Windows + LPARAM lParam; + +#if wxUSE_RICHEDIT + POINTL ptl; + if ( IsRich() ) + { + // for rich edit controls the position is passed iva the struct fields + ptl.x = pt.x; + ptl.y = pt.y; + lParam = (LPARAM)&ptl; + } + else +#endif // wxUSE_RICHEDIT + { + // for the plain ones, we are limited to 16 bit positions which are + // combined in a single 32 bit value + lParam = MAKELPARAM(pt.x, pt.y); + } + + LRESULT pos = SendMessage(GetHwnd(), EM_CHARFROMPOS, 0, lParam); + + if ( pos == -1 ) + { + // this seems to indicate an error... + return wxTE_HT_UNKNOWN; + } + +#if wxUSE_RICHEDIT + if ( !IsRich() ) +#endif // wxUSE_RICHEDIT + { + // for plain EDIT controls the higher word contains something else + pos = LOWORD(pos); + } + + + // next determine where it is relatively to our point: EM_CHARFROMPOS + // always returns the closest character but we need to be more precise, so + // double check that we really are where it pretends + POINTL ptReal; + +#if wxUSE_RICHEDIT + // FIXME: we need to distinguish between richedit 2 and 3 here somehow but + // we don't know how to do it + if ( IsRich() ) + { + SendMessage(GetHwnd(), EM_POSFROMCHAR, (WPARAM)&ptReal, pos); + } + else +#endif // wxUSE_RICHEDIT + { + LRESULT lRc = SendMessage(GetHwnd(), EM_POSFROMCHAR, pos, 0); + + if ( lRc == -1 ) + { + // this is apparently returned when pos corresponds to the last + // position + ptReal.x = + ptReal.y = 0; + } + else + { + ptReal.x = LOWORD(lRc); + ptReal.y = HIWORD(lRc); + } + } + + wxTextCtrlHitTestResult rc; + + if ( pt.y > ptReal.y + GetCharHeight() ) + rc = wxTE_HT_BELOW; + else if ( pt.x > ptReal.x + GetCharWidth() ) + rc = wxTE_HT_BEYOND; + else + rc = wxTE_HT_ON_TEXT; + + // finally translate to column/row + if ( !PositionToXY(pos, col, row) ) + { + wxFAIL_MSG( _T("PositionToXY() not expected to fail in HitTest()") ); + } + + return rc; +} + +// ---------------------------------------------------------------------------- +// +// ---------------------------------------------------------------------------- + void wxTextCtrl::ShowPosition(long pos) { HWND hWnd = GetHwnd(); @@ -1544,7 +1671,7 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) switch ( event.GetKeyCode() ) { case WXK_RETURN: - if ( !(m_windowStyle & wxTE_MULTILINE) ) + if ( !HasFlag(wxTE_MULTILINE) ) { wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId); InitCommandEvent(event); @@ -1557,10 +1684,26 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) break; case WXK_TAB: - // always produce navigation event - even if we process TAB + // always produce navigation event -- even if we process TAB // ourselves the fact that we got here means that the user code - // decided to skip processing of this TAB - probably to let it + // decided to skip processing of this TAB -- probably to let it // do its default job. + + // ok, so this is getting absolutely ridiculous but I don't see + // any other way to fix this bug: when a multiline text control is + // inside a wxFrame, we need to generate the navigation event as + // otherwise nothing happens at all, but when the same control is + // created inside a dialog, IsDialogMessage() *does* switch focus + // all by itself and so if we do it here as well, it is advanced + // twice and goes to the next control... to prevent this from + // happening we're doing this ugly check, the logic being that if + // we don't have focus then it had been already changed to the next + // control + // + // the right thing to do would, of course, be to understand what + // the hell is IsDialogMessage() doing but this is beyond my feeble + // forces at the moment unfortunately + if ( FindFocus() == this ) { wxNavigationKeyEvent eventNav; eventNav.SetDirection(!event.ShiftDown()); @@ -1577,9 +1720,9 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) event.Skip(); } -long wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - long lRc = wxTextCtrlBase::MSWWindowProc(nMsg, wParam, lParam); + WXLRESULT lRc = wxTextCtrlBase::MSWWindowProc(nMsg, wParam, lParam); if ( nMsg == WM_GETDLGCODE ) { @@ -1716,40 +1859,8 @@ WXHBRUSH wxTextCtrl::OnCtlColor(WXHDC pDC, WXHWND WXUNUSED(pWnd), WXUINT WXUNUSE return (WXHBRUSH)brush->GetResourceHandle(); } -// In WIN16, need to override normal erasing because -// Ctl3D doesn't use the wxWindows background colour. -#ifdef __WIN16__ -void wxTextCtrl::OnEraseBackground(wxEraseEvent& event) -{ - wxColour col(m_backgroundColour); - -#if wxUSE_CTL3D - if (m_useCtl3D) - col = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); -#endif - - RECT rect; - ::GetClientRect(GetHwnd(), &rect); - - COLORREF ref = wxColourToRGB(col); - HBRUSH hBrush = ::CreateSolidBrush(ref); - if ( !hBrush ) - wxLogLastError(wxT("CreateSolidBrush")); - - HDC hdc = (HDC)event.GetDC()->GetHDC(); - - int mode = ::SetMapMode(hdc, MM_TEXT); - - ::FillRect(hdc, &rect, hBrush); - ::DeleteObject(hBrush); - ::SetMapMode(hdc, mode); - -} -#endif // Win16 - bool wxTextCtrl::AdjustSpaceLimit() { -#ifndef __WIN16__ unsigned int limit = ::SendMessage(GetHwnd(), EM_GETLIMITTEXT, 0, 0); // HACK: we try to automatically extend the limit for the amount of text @@ -1791,7 +1902,6 @@ bool wxTextCtrl::AdjustSpaceLimit() ::SendMessage(GetHwnd(), EM_LIMITTEXT, limit, 0); } } -#endif // !Win16 // we changed the limit return TRUE; @@ -1812,13 +1922,17 @@ wxSize wxTextCtrl::DoGetBestSize() const int wText = DEFAULT_ITEM_WIDTH; - int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy); + int hText = cy; if ( m_windowStyle & wxTE_MULTILINE ) { hText *= wxMax(GetNumberOfLines(), 5); } //else: for single line control everything is ok + // we have to add the adjustments for the control height only once, not + // once per line, so do it after multiplication above + hText += EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy) - cy; + return wxSize(wText, hText); }