]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/textctrl.cpp
carbon cfm fixes
[wxWidgets.git] / src / msw / textctrl.cpp
index 113994facce2382911e21a744c1624f0e183c8aa..2f4136d212893849be5b9360842a94c5f8fa8cd0 100644 (file)
@@ -39,6 +39,7 @@
     #include "wx/log.h"
     #include "wx/app.h"
     #include "wx/menu.h"
+    #include "wx/math.h"
 #endif
 
 #include "wx/module.h"
@@ -102,6 +103,36 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule, wxModule)
 
 #endif // wxUSE_RICHEDIT
 
+// a small class used to set m_updatesCount to 0 (to filter duplicate events if
+// necessary) and to reset it back to -1 afterwards
+class UpdatesCountFilter
+{
+public:
+    UpdatesCountFilter(int& count)
+        : m_count(count)
+    {
+        wxASSERT_MSG( m_count == -1, _T("wrong initial m_updatesCount value") );
+
+        m_count = 0;
+    }
+
+    ~UpdatesCountFilter()
+    {
+        m_count = -1;
+    }
+
+    // return true if an event has been received
+    bool GotUpdate() const
+    {
+        return m_count == 1;
+    }
+
+private:
+    int& m_count;
+
+    DECLARE_NO_COPY_CLASS(UpdatesCountFilter)
+};
+
 // ----------------------------------------------------------------------------
 // event tables and other macros
 // ----------------------------------------------------------------------------
@@ -181,7 +212,7 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
     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)
@@ -218,9 +249,8 @@ void wxTextCtrl::Init()
 #endif // wxUSE_RICHEDIT
 
     m_privateContextMenu = NULL;
-    m_suppressNextUpdate = false;
+    m_updatesCount = -1;
     m_isNativeCaretShown = true;
-    m_isCaretAtEnd = true;
 }
 
 wxTextCtrl::~wxTextCtrl()
@@ -751,13 +781,8 @@ wxTextCtrl::StreamIn(const wxString& value,
     // the cast below is needed for broken (very) old mingw32 headers
     eds.pfnCallback = (EDITSTREAMCALLBACK)wxRichEditStreamIn;
 
-    // we're going to receive 2 EN_CHANGE notifications if we got any selection
-    // (same problem as in DoWriteText())
-    if ( selectionOnly && HasSelection() )
-    {
-        // so suppress one of them
-        m_suppressNextUpdate = true;
-    }
+    // same problem as in DoWriteText(): we can get multiple events here
+    UpdatesCountFilter ucf(m_updatesCount);
 
     ::SendMessage(GetHwnd(), EM_STREAMIN,
                   SF_TEXT |
@@ -765,6 +790,8 @@ wxTextCtrl::StreamIn(const wxString& value,
                   (selectionOnly ? SFF_SELECTION : 0),
                   (LPARAM)&eds);
 
+    wxASSERT_MSG( ucf.GotUpdate(), _T("EM_STREAMIN didn't send EN_UPDATE?") );
+
     if ( eds.dwError )
     {
         wxLogLastError(_T("EM_STREAMIN"));
@@ -906,36 +933,20 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
 #endif // wxUSE_RICHEDIT
     {
         // in some cases we get 2 EN_CHANGE notifications after the SendMessage
-        // call below which is confusing for the client code and so should be
-        // avoided
-        //
-        // these cases are: (a) plain EDIT controls if EM_REPLACESEL is used
-        // and there is a non empty selection currently and (b) rich text
-        // controls in any case
-        if (
-#if wxUSE_RICHEDIT
-            IsRich() ||
-#endif // wxUSE_RICHEDIT
-            (selectionOnly && HasSelection()) )
-        {
-            m_suppressNextUpdate = true;
-        }
+        // call (this happens for plain EDITs with EM_REPLACESEL and under some
+        // -- undetermined -- conditions with rich edit) and sometimes we don't
+        // get any events at all (plain EDIT with WM_SETTEXT), so ensure that
+        // we generate exactly one of them by ignoring all but the first one in
+        // SendUpdateEvent() and generating one ourselves if we hadn't got any
+        // notifications from Windows
+        UpdatesCountFilter ucf(m_updatesCount);
 
         ::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
                       0, (LPARAM)valueDos.c_str());
 
-        // OTOH, non rich text controls don't generate any events at all when
-        // we use WM_SETTEXT -- have to emulate them here
-        if ( !selectionOnly
-#if wxUSE_RICHEDIT
-                && !IsRich()
-#endif // wxUSE_RICHEDIT
-           )
+        if ( !ucf.GotUpdate() )
         {
-            // Windows already sends an update event for single-line
-            // controls.
-            if ( m_windowStyle & wxTE_MULTILINE )
-                SendUpdateEvent();
+            SendUpdateEvent();
         }
     }
 }
@@ -1078,8 +1089,6 @@ void wxTextCtrl::SetEditable(bool editable)
 void wxTextCtrl::SetInsertionPoint(long pos)
 {
     DoSetSelection(pos, pos);
-
-    m_isCaretAtEnd = pos == GetLastPosition();
 }
 
 void wxTextCtrl::SetInsertionPointEnd()
@@ -1089,9 +1098,8 @@ 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;
     }
 
@@ -1129,7 +1137,7 @@ long wxTextCtrl::GetInsertionPoint() const
     return Pos & 0xFFFF;
 }
 
-long wxTextCtrl::GetLastPosition() const
+wxTextPos wxTextCtrl::GetLastPosition() const
 {
     int numLines = GetNumberOfLines();
     long posStartLastLine = XYToPosition(0, numLines - 1);
@@ -1472,9 +1480,6 @@ void wxTextCtrl::ShowPosition(long pos)
 
     if (linesToScroll != 0)
       (void)::SendMessage(hWnd, EM_LINESCROLL, (WPARAM)0, (LPARAM)linesToScroll);
-
-    // be pessimistic
-    m_isCaretAtEnd = false;
 }
 
 long wxTextCtrl::GetLengthOfLineContainingPos(long pos) const
@@ -1551,9 +1556,6 @@ void wxTextCtrl::Undo()
     if (CanUndo())
     {
         ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
-
-        // it's not necessarily at the end any more
-        m_isCaretAtEnd = false;
     }
 }
 
@@ -1568,9 +1570,6 @@ void wxTextCtrl::Redo()
 #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;
     }
 }
 
@@ -1801,18 +1800,29 @@ WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
 
 bool wxTextCtrl::SendUpdateEvent()
 {
-    // is event reporting suspended?
-    if ( m_suppressNextUpdate )
+    switch ( m_updatesCount )
     {
-        // do process the next one
-        m_suppressNextUpdate = false;
+        case 0:
+            // remember that we've got an update
+            m_updatesCount++;
+            break;
 
-        return false;
+        case 1:
+            // we had already sent one event since the last control modification
+            return false;
+
+        default:
+            wxFAIL_MSG( _T("unexpected wxTextCtrl::m_updatesCount value") );
+            // fall through
+
+        case -1:
+            // we hadn't updated the control ourselves, this event comes from
+            // the user, don't need to ignore it nor update the count
+            break;
     }
 
     wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
     InitCommandEvent(event);
-    event.SetString(GetValue());
 
     return ProcessCommand(event);
 }
@@ -1856,38 +1866,12 @@ bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
     return true;
 }
 
-WXHBRUSH wxTextCtrl::OnCtlColor(WXHDC pDC, WXHWND WXUNUSED(pWnd), WXUINT WXUNUSED(nCtlColor),
-#if wxUSE_CTL3D
-                               WXUINT message,
-                               WXWPARAM wParam,
-                               WXLPARAM lParam
-#else
-                               WXUINT WXUNUSED(message),
-                               WXWPARAM WXUNUSED(wParam),
-                               WXLPARAM WXUNUSED(lParam)
-#endif
-    )
+WXHBRUSH wxTextCtrl::MSWControlColor(WXHDC hDC)
 {
-#if wxUSE_CTL3D
-    if ( m_useCtl3D )
-    {
-        HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam);
-        return (WXHBRUSH) hbrush;
-    }
-#endif // wxUSE_CTL3D
-
-    HDC hdc = (HDC)pDC;
-    wxColour colBack = GetBackgroundColour();
-
-    if (!IsEnabled() && (GetWindowStyle() & wxTE_MULTILINE) == 0)
-        colBack = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
+    if ( !IsEnabled() && !HasFlag(wxTE_MULTILINE) )
+        return MSWControlColorDisabled(hDC);
 
-    ::SetBkColor(hdc, wxColourToRGB(colBack));
-    ::SetTextColor(hdc, wxColourToRGB(GetForegroundColour()));
-
-    wxBrush *brush = wxTheBrushList->FindOrCreateBrush(colBack, wxSOLID);
-
-    return (WXHBRUSH)brush->GetResourceHandle();
+    return wxTextCtrlBase::MSWControlColorSolid(hDC);
 }
 
 bool wxTextCtrl::AdjustSpaceLimit()
@@ -2046,7 +2030,7 @@ void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event)
     event.Enable(GetLastPosition() > 0);
 }
 
-void wxTextCtrl::OnRightClick(wxMouseEvent& event)
+void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
 {
 #if wxUSE_RICHEDIT
     if (IsRich())
@@ -2064,7 +2048,7 @@ void wxTextCtrl::OnRightClick(wxMouseEvent& event)
             m_privateContextMenu->AppendSeparator();
             m_privateContextMenu->Append(wxID_SELECTALL, _("Select &All"));
         }
-        PopupMenu(m_privateContextMenu, event.GetPosition());
+        PopupMenu(m_privateContextMenu);
         return;
     }
     else
@@ -2081,6 +2065,23 @@ void wxTextCtrl::OnSetFocus(wxFocusEvent& WXUNUSED(event))
     }
 }
 
+// ----------------------------------------------------------------------------
+// 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).
+// ----------------------------------------------------------------------------
+
+wxVisualAttributes wxTextCtrl::GetDefaultAttributes() const
+{
+    wxVisualAttributes attrs;
+    attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+    attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
+    attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); //white
+
+    return attrs;
+}
+
 // the rest of the file only deals with the rich edit controls
 #if wxUSE_RICHEDIT
 
@@ -2184,23 +2185,6 @@ bool wxTextCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
     return wxTextCtrlBase::MSWOnNotify(idCtrl, lParam, result);
 }
 
-// ----------------------------------------------------------------------------
-// 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). 
-// ----------------------------------------------------------------------------
-
-wxVisualAttributes wxTextCtrl::GetDefaultAttributes() const
-{
-    wxVisualAttributes attrs;
-    attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
-    attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
-    attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); //white
-
-    return attrs;
-}
-
 // ----------------------------------------------------------------------------
 // colour setting for the rich edit controls
 // ----------------------------------------------------------------------------
@@ -2469,7 +2453,7 @@ bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
     {
         // 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);
     }
 
@@ -2534,7 +2518,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style)
     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