// declarations
// ============================================================================
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
- #pragma implementation "textctrl.h"
-#endif
-
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
class wxRichEditModule : public wxModule
{
public:
+ enum Version
+ {
+ Version_1, // riched32.dll
+ Version_2or3, // both use riched20.dll
+ Version_41, // msftedit.dll (XP SP1 and Windows 2003)
+ Version_Max
+ };
+
virtual bool OnInit();
virtual void OnExit();
- // load the richedit DLL of at least of required version
- static bool Load(int version = 1);
+ // load the richedit DLL for the specified version of rich edit
+ static bool Load(Version version);
private:
// the handles to richedit 1.0 and 2.0 (or 3.0) DLLs
- static HINSTANCE ms_hRichEdit[2];
+ static HINSTANCE ms_hRichEdit[Version_Max];
DECLARE_DYNAMIC_CLASS(wxRichEditModule)
};
-HINSTANCE wxRichEditModule::ms_hRichEdit[2] = { NULL, NULL };
+HINSTANCE wxRichEditModule::ms_hRichEdit[Version_Max] = { NULL, NULL, NULL };
IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule, wxModule)
EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
#if wxUSE_RICHEDIT
- EVT_RIGHT_UP(wxTextCtrl::OnRightClick)
+ EVT_CONTEXT_MENU(wxTextCtrl::OnContextMenu)
#endif
EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
m_privateContextMenu = NULL;
m_updatesCount = -1;
m_isNativeCaretShown = true;
- m_isCaretAtEnd = true;
}
wxTextCtrl::~wxTextCtrl()
// do create the control - either an EDIT or RICHEDIT
wxString windowClass = wxT("EDIT");
+#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
+ // A control that capitalizes the first letter
+ if (style & wxTE_CAPITALIZE)
+ windowClass = wxT("CAPEDIT");
+#endif
+
#if wxUSE_RICHEDIT
if ( m_windowStyle & wxTE_AUTO_URL )
{
// we need to load the richedit DLL before creating the rich edit control
if ( m_windowStyle & wxTE_RICH )
{
- static bool s_errorGiven = false;// MT-FIXME
-
- // Which version do we need? Use 1.0 by default because it is much more
- // like the the standard EDIT or 2.0 if explicitly requested, but use
- // only 2.0 in Unicode mode as 1.0 doesn't support Unicode at all
+ // versions 2.0, 3.0 and 4.1 of rich edit are mostly compatible with
+ // each other but not with version 1.0, so we have separate flags for
+ // the version 1.0 and the others (and so m_verRichEdit may be 0 (plain
+ // EDIT control), 1 for version 1.0 or 2 for any higher version)
//
- // TODO: RichEdit 3.0 is apparently capable of emulating RichEdit 1.0
- // (and thus EDIT) much better than RichEdit 2.0 so we probably
- // should use 3.0 if available as it is the best of both worlds -
- // but as I can't test it right now I don't do it (VZ)
+ // notice that 1.0 has no Unicode support at all so in Unicode build we
+ // must use another version
+
#if wxUSE_UNICODE
- const int verRichEdit = 2;
+ m_verRichEdit = 2;
#else // !wxUSE_UNICODE
- int verRichEdit = m_windowStyle & wxTE_RICH2 ? 2 : 1;
+ m_verRichEdit = m_windowStyle & wxTE_RICH2 ? 2 : 1;
#endif // wxUSE_UNICODE/!wxUSE_UNICODE
- // only give the error msg once if the DLL can't be loaded
- if ( !s_errorGiven )
+ if ( m_verRichEdit == 2 )
{
- // try to load the RichEdit DLL (will do nothing if already done)
- if ( !wxRichEditModule::Load(verRichEdit) )
+ if ( wxRichEditModule::Load(wxRichEditModule::Version_41) )
{
-#if !wxUSE_UNICODE
- // try another version?
- verRichEdit = 3 - verRichEdit; // 1 <-> 2
-
- if ( !wxRichEditModule::Load(verRichEdit) )
-#endif // wxUSE_UNICODE
- {
- wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll"));
-
- s_errorGiven = true;
- }
+ // yes, class name for version 4.1 really is 5.0
+ windowClass = _T("RICHEDIT50W");
+ }
+ else if ( wxRichEditModule::Load(wxRichEditModule::Version_2or3) )
+ {
+ windowClass = _T("RichEdit20")
+#if wxUSE_UNICODE
+ _T("W");
+#else // ANSI
+ _T("A");
+#endif // Unicode/ANSI
+ }
+ else // failed to load msftedit.dll and riched20.dll
+ {
+ m_verRichEdit = 1;
}
}
- // have we managed to load any richedit version?
- if ( !s_errorGiven )
+ if ( m_verRichEdit == 1 )
{
- m_verRichEdit = verRichEdit;
- if ( m_verRichEdit == 1 )
+ if ( wxRichEditModule::Load(wxRichEditModule::Version_1) )
{
- windowClass = wxT("RICHEDIT");
+ windowClass = _T("RICHEDIT");
}
- else
+ else // failed to load any richedit control DLL
{
-#ifndef RICHEDIT_CLASS
- wxString RICHEDIT_CLASS;
- RICHEDIT_CLASS.Printf(_T("RichEdit%d0"), m_verRichEdit);
-#if wxUSE_UNICODE
- RICHEDIT_CLASS += _T('W');
-#else // ANSI
- RICHEDIT_CLASS += _T('A');
-#endif // Unicode/ANSI
-#endif // !RICHEDIT_CLASS
+ // only give the error msg once if the DLL can't be loaded
+ static bool s_errorGiven = false; // MT ok as only used by GUI
- windowClass = RICHEDIT_CLASS;
+ if ( !s_errorGiven )
+ {
+ wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll"));
+
+ s_errorGiven = true;
+ }
+
+ m_verRichEdit = 0;
}
}
}
// we also need EN_MSGFILTER for richedit 1.0 for the reasons
// explained in its handler
mask |= ENM_MOUSEEVENTS;
+
+ // we also need to force the appearance of the vertical scrollbar
+ // initially as otherwise the control doesn't refresh correctly
+ // after resize: but once the vertical scrollbar had been shown
+ // (even if it's subsequently hidden) it does
+ //
+ // this is clearly a bug and for now it has been only noticed under
+ // Windows XP, so if we're sure it works correctly under other
+ // systems we could do this only for XP
+ SetSize(-1, 1); // 1 is small enough to force vert scrollbar
+ SetSize(size);
}
else if ( m_windowStyle & wxTE_AUTO_URL )
{
void wxTextCtrl::SetInsertionPoint(long pos)
{
DoSetSelection(pos, pos);
-
- m_isCaretAtEnd = pos == GetLastPosition();
}
void wxTextCtrl::SetInsertionPointEnd()
// if it doesn't actually move the caret anywhere and so the simple fact of
// doing it results in horrible flicker when appending big amounts of text
// to the control in a few chunks (see DoAddText() test in the text sample)
- if ( m_isCaretAtEnd || GetInsertionPoint() == GetLastPosition() )
+ if ( GetInsertionPoint() == GetLastPosition() )
{
- m_isCaretAtEnd = true;
return;
}
return Pos & 0xFFFF;
}
-long wxTextCtrl::GetLastPosition() const
+wxTextPos wxTextCtrl::GetLastPosition() const
{
int numLines = GetNumberOfLines();
long posStartLastLine = XYToPosition(0, numLines - 1);
if (linesToScroll != 0)
(void)::SendMessage(hWnd, EM_LINESCROLL, (WPARAM)0, (LPARAM)linesToScroll);
-
- // be pessimistic
- m_isCaretAtEnd = false;
}
long wxTextCtrl::GetLengthOfLineContainingPos(long pos) const
void wxTextCtrl::SetMaxLength(unsigned long len)
{
#if wxUSE_RICHEDIT
- if (IsRich())
- ::SendMessage(GetHwnd(), EM_EXLIMITTEXT, 0, (LPARAM) (DWORD) len);
+ if ( IsRich() )
+ {
+ ::SendMessage(GetHwnd(), EM_EXLIMITTEXT, 0, len ? len : 0x7fffffff);
+ }
else
-#endif
- ::SendMessage(GetHwnd(), EM_LIMITTEXT, len, 0);
+#endif // wxUSE_RICHEDIT
+ {
+ if ( len >= 0xffff )
+ {
+ // this will set it to a platform-dependent maximum (much more
+ // than 64Kb under NT)
+ len = 0;
+ }
+
+ ::SendMessage(GetHwnd(), EM_LIMITTEXT, len, 0);
+ }
}
// ----------------------------------------------------------------------------
if (CanUndo())
{
::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
-
- // it's not necessarily at the end any more
- m_isCaretAtEnd = false;
}
}
#endif
// Same as Undo, since Undo undoes the undo, i.e. a redo.
::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
-
- // it's not necessarily at the end any more
- m_isCaretAtEnd = false;
}
}
// Insert tab since calling the default Windows handler
// doesn't seem to do it
WriteText(wxT("\t"));
+ return;
}
break;
}
return true;
}
-WXHBRUSH wxTextCtrl::MSWControlColor(WXHDC hDC)
+WXHBRUSH wxTextCtrl::MSWControlColor(WXHDC hDC, WXHWND hWnd)
{
if ( !IsEnabled() && !HasFlag(wxTE_MULTILINE) )
return MSWControlColorDisabled(hDC);
- return wxTextCtrlBase::MSWControlColorSolid(hDC);
+ return wxTextCtrlBase::MSWControlColor(hDC, hWnd);
}
-bool wxTextCtrl::AdjustSpaceLimit()
+bool wxTextCtrl::HasSpaceLimit(unsigned int *len) const
{
- unsigned int limit = ::SendMessage(GetHwnd(), EM_GETLIMITTEXT, 0, 0);
-
// HACK: we try to automatically extend the limit for the amount of text
// to allow (interactively) entering more than 64Kb of text under
// Win9x but we shouldn't reset the text limit which was previously
// set explicitly with SetMaxLength()
//
- // we could solve this by storing the limit we set in wxTextCtrl but
- // to save space we prefer to simply test here the actual limit
- // value: we consider that SetMaxLength() can only be called for
- // values < 32Kb
- if ( limit < 0x8000 )
- {
- // we've got more text than limit set by SetMaxLength()
+ // Unfortunately there is no EM_GETLIMITTEXTSETBYUSER and so we don't
+ // know the limit we set (if any). We could solve this by storing the
+ // limit we set in wxTextCtrl but to save space we prefer to simply
+ // test here the actual limit value: we consider that SetMaxLength()
+ // can only be called for small values while EN_MAXTEXT is only sent
+ // for large values (in practice the default limit seems to be 30000
+ // but make it smaller just to be on the safe side)
+ *len = ::SendMessage(GetHwnd(), EM_GETLIMITTEXT, 0, 0);
+ return *len < 10001;
+
+}
+
+bool wxTextCtrl::AdjustSpaceLimit()
+{
+ unsigned int limit;
+ if ( HasSpaceLimit(&limit) )
return false;
- }
unsigned int len = ::GetWindowTextLength(GetHwnd());
if ( len >= limit )
{
- limit = len + 0x8000; // 32Kb
-
-#if wxUSE_RICHEDIT
- if ( IsRich() )
- {
- // as a nice side effect, this also allows passing limit > 64Kb
- ::SendMessage(GetHwnd(), EM_EXLIMITTEXT, 0, limit);
- }
- else
-#endif // wxUSE_RICHEDIT
- {
- if ( limit > 0xffff )
- {
- // this will set it to a platform-dependent maximum (much more
- // than 64Kb under NT)
- limit = 0;
- }
-
- ::SendMessage(GetHwnd(), EM_LIMITTEXT, limit, 0);
- }
+ // increment in 32Kb chunks
+ SetMaxLength(len + 0x8000);
}
// we changed the limit
int hText = cy;
if ( m_windowStyle & wxTE_MULTILINE )
{
- hText *= wxMax(GetNumberOfLines(), 5);
+ hText *= wxMax(wxMin(GetNumberOfLines(), 10), 2);
}
//else: for single line control everything is ok
event.Enable(GetLastPosition() > 0);
}
-void wxTextCtrl::OnRightClick(wxMouseEvent& event)
+void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
{
#if wxUSE_RICHEDIT
if (IsRich())
m_privateContextMenu->AppendSeparator();
m_privateContextMenu->Append(wxID_SELECTALL, _("Select &All"));
}
- PopupMenu(m_privateContextMenu, event.GetPosition());
+ PopupMenu(m_privateContextMenu);
return;
}
else
// Default colors for MSW text control
//
// Set default background color to the native white instead of
-// the default wxSYS_COLOUR_BTNFACE (is triggered with wxNullColour).
+// the default wxSYS_COLOUR_BTNFACE (is triggered with wxNullColour).
// ----------------------------------------------------------------------------
wxVisualAttributes wxTextCtrl::GetDefaultAttributes() const
{
// we have to do this or the style wouldn't apply for the text typed by
// the user
- long posLast = GetLastPosition();
+ wxTextPos posLast = GetLastPosition();
SetStyle(posLast, posLast, m_defaultStyle);
}
wxStrcpy(lf.lfFaceName, cf.szFaceName);
//NOTE: we _MUST_ set each of these values to _something_ since we
- //do not call wxZeroMemory on the LOGFONT lf
+ //do not call wxZeroMemory on the LOGFONT lf
if (cf.dwEffects & CFE_ITALIC)
lf.lfItalic = TRUE;
else
// wxRichEditModule
// ----------------------------------------------------------------------------
+static const HINSTANCE INVALID_HINSTANCE = (HINSTANCE)-1;
+
bool wxRichEditModule::OnInit()
{
// don't do anything - we will load it when needed
{
for ( size_t i = 0; i < WXSIZEOF(ms_hRichEdit); i++ )
{
- if ( ms_hRichEdit[i] )
+ if ( ms_hRichEdit[i] && ms_hRichEdit[i] != INVALID_HINSTANCE )
{
::FreeLibrary(ms_hRichEdit[i]);
ms_hRichEdit[i] = NULL;
}
/* static */
-bool wxRichEditModule::Load(int version)
+bool wxRichEditModule::Load(Version version)
{
- // we don't support loading richedit 3.0 as I don't know how to distinguish
- // it from 2.0 anyhow
- wxCHECK_MSG( version == 1 || version == 2, false,
- _T("incorrect richedit control version requested") );
-
- // make it the index in the array
- version--;
-
- if ( ms_hRichEdit[version] == (HINSTANCE)-1 )
+ if ( ms_hRichEdit[version] == INVALID_HINSTANCE )
{
// we had already tried to load it and failed
return false;
return true;
}
- wxString dllname = version ? _T("riched20") : _T("riched32");
- dllname += _T(".dll");
+ static const wxChar *dllnames[] =
+ {
+ _T("riched32"),
+ _T("riched20"),
+ _T("msftedit"),
+ };
+
+ wxCOMPILE_TIME_ASSERT( WXSIZEOF(dllnames) == Version_Max,
+ RichEditDllNamesVersionsMismatch );
- ms_hRichEdit[version] = ::LoadLibrary(dllname);
+ ms_hRichEdit[version] = ::LoadLibrary(dllnames[version]);
if ( !ms_hRichEdit[version] )
{
- wxLogSysError(_("Could not load Rich Edit DLL '%s'"), dllname.c_str());
-
- ms_hRichEdit[version] = (HINSTANCE)-1;
+ ms_hRichEdit[version] = INVALID_HINSTANCE;
return false;
}