X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6a98321125338dbd196c562cf852f80f34551f02..d3e780ecdf69233c872d51216eedbc64a1b6db25:/src/msw/textctrl.cpp diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 6a3af8adab..fa977a9896 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) @@ -530,32 +530,49 @@ wxString wxTextCtrl::GetRange(long from, long to) const if ( to == -1 ) to = len; +#if !wxUSE_UNICODE // 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); } } // StreamOut() wasn't used or failed, try to do it in normal way if ( str.empty() ) +#endif // !wxUSE_UNICODE { // alloc one extra WORD as needed by the control wxStringBuffer tmp(str, ++len); @@ -563,7 +580,7 @@ wxString wxTextCtrl::GetRange(long from, long to) const TEXTRANGE textRange; textRange.chrg.cpMin = from; - textRange.chrg.cpMax = to == -1 ? len : to; + textRange.chrg.cpMax = to; textRange.lpstrText = p; (void)SendMessage(GetHwnd(), EM_GETTEXTRANGE, @@ -620,6 +637,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 { @@ -632,9 +652,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) @@ -663,24 +680,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; } @@ -765,9 +795,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 @@ -784,13 +818,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); } } @@ -1218,6 +1256,23 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret) #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; +} + // ---------------------------------------------------------------------------- // Editing // ---------------------------------------------------------------------------- @@ -1227,13 +1282,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) @@ -1241,25 +1290,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); @@ -1270,6 +1310,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 @@ -1317,6 +1361,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(); @@ -1542,7 +1679,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); @@ -1555,10 +1692,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()); @@ -1575,9 +1728,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 ) { @@ -1810,13 +1963,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); }