]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/scrlwing.cpp
Fixed bug in optimization for character input, affecting first paragraph in the buffer.
[wxWidgets.git] / src / generic / scrlwing.cpp
index ad1b3813991b1eb3b57938510db1395a662b95f4..4d4c52bc701f7a64c6ba46e96705a3905fed2961 100644 (file)
 // headers
 // ----------------------------------------------------------------------------
 
-#ifdef __VMS
-#define XtDisplay XTDISPLAY
-#endif
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
     #pragma hdrstop
 #endif
 
+#ifdef __VMS
+#define XtDisplay XTDISPLAY
+#endif
+
 #include "wx/scrolwin.h"
 
 #ifndef WX_PRECOMP
     #include "wx/sizer.h"
 #endif
 
+#ifdef __WXMAC__
+#include "wx/scrolbar.h"
+#endif
+
 #include "wx/recguard.h"
 
 #ifdef __WXMSW__
@@ -231,16 +235,18 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
         }
     }
 
-    // reset the skipped flag to false as it might have been set to true in
-    // ProcessEvent() above
-    event.Skip(false);
-
     if ( evType == wxEVT_PAINT )
     {
         m_scrollHelper->HandleOnPaint((wxPaintEvent &)event);
         return true;
     }
 
+    // reset the skipped flag (which might have been set to true in
+    // ProcessEvent() above) to be able to test it below
+    bool wasSkipped = event.GetSkipped();
+    if ( wasSkipped )
+        event.Skip(false);
+
     if ( evType == wxEVT_SCROLLWIN_TOP ||
          evType == wxEVT_SCROLLWIN_BOTTOM ||
          evType == wxEVT_SCROLLWIN_LINEUP ||
@@ -250,8 +256,16 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
          evType == wxEVT_SCROLLWIN_THUMBTRACK ||
          evType == wxEVT_SCROLLWIN_THUMBRELEASE )
     {
-            m_scrollHelper->HandleOnScroll((wxScrollWinEvent &)event);
-            return !event.GetSkipped();
+        m_scrollHelper->HandleOnScroll((wxScrollWinEvent &)event);
+        if ( !event.GetSkipped() )
+        {
+            // it makes sense to indicate that we processed the message as we
+            // did scroll the window (and also notice that wxAutoScrollTimer
+            // relies on our return value to stop scrolling when we are at top
+            // or bottom already)
+            processed = true;
+            wasSkipped = false;
+        }
     }
 
     if ( evType == wxEVT_ENTER_WINDOW )
@@ -263,18 +277,29 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
         m_scrollHelper->HandleOnMouseLeave((wxMouseEvent &)event);
     }
 #if wxUSE_MOUSEWHEEL
+    // Use GTK's own scroll wheel handling in GtkScrolledWindow
+#ifndef __WXGTK20__
     else if ( evType == wxEVT_MOUSEWHEEL )
     {
         m_scrollHelper->HandleOnMouseWheel((wxMouseEvent &)event);
+        return true;
     }
+#endif
 #endif // wxUSE_MOUSEWHEEL
     else if ( evType == wxEVT_CHAR )
     {
         m_scrollHelper->HandleOnChar((wxKeyEvent &)event);
-        return !event.GetSkipped();
+        if ( !event.GetSkipped() )
+        {
+            processed = true;
+            wasSkipped = false;
+        }
     }
 
-    return false;
+    if ( processed )
+        event.Skip(wasSkipped);
+
+    return processed;
 }
 
 // ----------------------------------------------------------------------------
@@ -311,6 +336,8 @@ wxScrollHelper::wxScrollHelper(wxWindow *win)
     m_handler = NULL;
 
     m_win = win;
+    
+    m_win->SetScrollHelper( this );
 
     // by default, the associated window is also the target window
     DoSetTargetWindow(win);
@@ -460,21 +487,10 @@ void wxScrollHelper::HandleOnScroll(wxScrollWinEvent& event)
         return;
     }
 
-    int orient = event.GetOrientation();
-    if (orient == wxHORIZONTAL)
-    {
-        m_xScrollPosition += nScrollInc;
-        m_win->SetScrollPos(wxHORIZONTAL, m_xScrollPosition);
-    }
-    else
-    {
-        m_yScrollPosition += nScrollInc;
-        m_win->SetScrollPos(wxVERTICAL, m_yScrollPosition);
-    }
-
     bool needsRefresh = false;
     int dx = 0,
         dy = 0;
+    int orient = event.GetOrientation();
     if (orient == wxHORIZONTAL)
     {
        if ( m_xScrollingEnabled )
@@ -498,6 +514,30 @@ void wxScrollHelper::HandleOnScroll(wxScrollWinEvent& event)
         }
     }
 
+    if ( !needsRefresh )
+    {
+        // flush all pending repaints before we change m_{x,y}ScrollPosition, as
+        // otherwise invalidated area could be updated incorrectly later when
+        // ScrollWindow() makes sure they're repainted before scrolling them
+#ifdef __WXMAC__
+        // wxWindowMac is taking care of making sure the update area is correctly
+        // set up, while not forcing an immediate redraw
+#else
+        m_targetWindow->Update();
+#endif
+    }
+
+    if (orient == wxHORIZONTAL)
+    {
+        m_xScrollPosition += nScrollInc;
+        m_win->SetScrollPos(wxHORIZONTAL, m_xScrollPosition);
+    }
+    else
+    {
+        m_yScrollPosition += nScrollInc;
+        m_win->SetScrollPos(wxVERTICAL, m_yScrollPosition);
+    }
+
     if ( needsRefresh )
     {
         m_targetWindow->Refresh(true, GetScrollRect());
@@ -561,49 +601,36 @@ int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event)
 
     if (orient == wxHORIZONTAL)
     {
-        if (m_xScrollPixelsPerLine > 0)
+        if ( m_xScrollPosition + nScrollInc < 0 )
         {
-            if ( m_xScrollPosition + nScrollInc < 0 )
-            {
-                // As -ve as we can go
-                nScrollInc = -m_xScrollPosition;
-            }
-            else // check for the other bound
+            // As -ve as we can go
+            nScrollInc = -m_xScrollPosition;
+        }
+        else // check for the other bound
+        {
+            const int posMax = m_xScrollLines - m_xScrollLinesPerPage;
+            if ( m_xScrollPosition + nScrollInc > posMax )
             {
-                const int posMax = m_xScrollLines - m_xScrollLinesPerPage;
-                if ( m_xScrollPosition + nScrollInc > posMax )
-                {
-                    // As +ve as we can go
-                    nScrollInc = posMax - m_xScrollPosition;
-                }
+                // As +ve as we can go
+                nScrollInc = posMax - m_xScrollPosition;
             }
         }
-        else
-            m_targetWindow->Refresh(true, GetScrollRect());
     }
-    else
+    else // wxVERTICAL
     {
-        if ( m_yScrollPixelsPerLine > 0 )
+        if ( m_yScrollPosition + nScrollInc < 0 )
         {
-            if ( m_yScrollPosition + nScrollInc < 0 )
-            {
-                // As -ve as we can go
-                nScrollInc = -m_yScrollPosition;
-            }
-            else // check for the other bound
-            {
-                const int posMax = m_yScrollLines - m_yScrollLinesPerPage;
-                if ( m_yScrollPosition + nScrollInc > posMax )
-                {
-                    // As +ve as we can go
-                    nScrollInc = posMax - m_yScrollPosition;
-                }
-            }
+            // As -ve as we can go
+            nScrollInc = -m_yScrollPosition;
         }
-        else
+        else // check for the other bound
         {
-            // VZ: why do we do this? (FIXME)
-            m_targetWindow->Refresh(true, GetScrollRect());
+            const int posMax = m_yScrollLines - m_yScrollLinesPerPage;
+            if ( m_yScrollPosition + nScrollInc > posMax )
+            {
+                // As +ve as we can go
+                nScrollInc = posMax - m_yScrollPosition;
+            }
         }
     }
 
@@ -813,8 +840,17 @@ void wxScrollHelper::AdjustScrollbars()
 void wxScrollHelper::DoPrepareDC(wxDC& dc)
 {
     wxPoint pt = dc.GetDeviceOrigin();
-    dc.SetDeviceOrigin( pt.x - m_xScrollPosition * m_xScrollPixelsPerLine,
-                        pt.y - m_yScrollPosition * m_yScrollPixelsPerLine );
+#ifdef __WXGTK__
+    // It may actually be correct to always query
+    // the m_sign from the DC here, but I leve the
+    // #ifdef GTK for now.
+    if (m_win->GetLayoutDirection() == wxLayout_RightToLeft)
+        dc.SetDeviceOrigin( pt.x + m_xScrollPosition * m_xScrollPixelsPerLine,
+                            pt.y - m_yScrollPosition * m_yScrollPixelsPerLine );
+    else
+#endif
+        dc.SetDeviceOrigin( pt.x - m_xScrollPosition * m_xScrollPixelsPerLine,
+                            pt.y - m_yScrollPosition * m_yScrollPixelsPerLine );
     dc.SetUserScale( m_scaleX, m_scaleY );
 }
 
@@ -844,6 +880,15 @@ void wxScrollHelper::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const
         *y_unit = m_yScrollPixelsPerLine;
 }
 
+
+int wxScrollHelper::GetScrollLines( int orient ) const
+{
+    if ( orient == wxHORIZONTAL )
+        return m_xScrollLines;
+    else
+        return m_yScrollLines;
+}
+
 int wxScrollHelper::GetScrollPageSize(int orient) const
 {
     if ( orient == wxHORIZONTAL )
@@ -874,47 +919,64 @@ void wxScrollHelper::Scroll( int x_pos, int y_pos )
     int w = 0, h = 0;
     GetTargetSize(&w, &h);
 
+    // compute new position:
+    int new_x = m_xScrollPosition;
+    int new_y = m_yScrollPosition;
+
     if ((x_pos != -1) && (m_xScrollPixelsPerLine))
     {
-        int old_x = m_xScrollPosition;
-        m_xScrollPosition = x_pos;
+        new_x = x_pos;
 
         // Calculate page size i.e. number of scroll units you get on the
         // current client window
-        int noPagePositions = (int) ( (w/(double)m_xScrollPixelsPerLine) + 0.5 );
+        int noPagePositions = w/m_xScrollPixelsPerLine;
         if (noPagePositions < 1) noPagePositions = 1;
 
         // Correct position if greater than extent of canvas minus
         // the visible portion of it or if below zero
-        m_xScrollPosition = wxMin( m_xScrollLines-noPagePositions, m_xScrollPosition );
-        m_xScrollPosition = wxMax( 0, m_xScrollPosition );
-
-        if (old_x != m_xScrollPosition) {
-            m_win->SetScrollPos( wxHORIZONTAL, m_xScrollPosition );
-            m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0,
-                                          GetScrollRect() );
-        }
+        new_x = wxMin( m_xScrollLines-noPagePositions, new_x );
+        new_x = wxMax( 0, new_x );
     }
     if ((y_pos != -1) && (m_yScrollPixelsPerLine))
     {
-        int old_y = m_yScrollPosition;
-        m_yScrollPosition = y_pos;
+        new_y = y_pos;
 
         // Calculate page size i.e. number of scroll units you get on the
         // current client window
-        int noPagePositions = (int) ( (h/(double)m_yScrollPixelsPerLine) + 0.5 );
+        int noPagePositions = h/m_yScrollPixelsPerLine;
         if (noPagePositions < 1) noPagePositions = 1;
 
         // Correct position if greater than extent of canvas minus
         // the visible portion of it or if below zero
-        m_yScrollPosition = wxMin( m_yScrollLines-noPagePositions, m_yScrollPosition );
-        m_yScrollPosition = wxMax( 0, m_yScrollPosition );
+        new_y = wxMin( m_yScrollLines-noPagePositions, new_y );
+        new_y = wxMax( 0, new_y );
+    }
 
-        if (old_y != m_yScrollPosition) {
-            m_win->SetScrollPos( wxVERTICAL, m_yScrollPosition );
-            m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine,
-                                          GetScrollRect() );
-        }
+    if ( new_x == m_xScrollPosition && new_y == m_yScrollPosition )
+        return; // nothing to do, the position didn't change
+
+    // flush all pending repaints before we change m_{x,y}ScrollPosition, as
+    // otherwise invalidated area could be updated incorrectly later when
+    // ScrollWindow() makes sure they're repainted before scrolling them
+    m_targetWindow->Update();
+
+    // update the position and scroll the window now:
+    if (m_xScrollPosition != new_x)
+    {
+        int old_x = m_xScrollPosition;
+        m_xScrollPosition = new_x;
+        m_win->SetScrollPos( wxHORIZONTAL, new_x );
+        m_targetWindow->ScrollWindow( (old_x-new_x)*m_xScrollPixelsPerLine, 0,
+                                      GetScrollRect() );
+    }
+
+    if (m_yScrollPosition != new_y)
+    {
+        int old_y = m_yScrollPosition;
+        m_yScrollPosition = new_y;
+        m_win->SetScrollPos( wxVERTICAL, new_y );
+        m_targetWindow->ScrollWindow( 0, (old_y-new_y)*m_yScrollPixelsPerLine,
+                                      GetScrollRect() );
     }
 }
 
@@ -936,33 +998,7 @@ void wxScrollHelper::GetViewStart (int *x, int *y) const
 void wxScrollHelper::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) const
 {
     if ( xx )
-    {
-        if ((m_xScrollLines == 0) || (m_xScrollPixelsPerLine == 0))
-        {
-            // nothing to do
-            *xx = x;
-        }
-        else
-        {
-#ifdef __WXGTK__
-            if (m_win->GetLayoutDirection() == wxLayout_RightToLeft)
-            {
-                int w = 0, h = 0;
-                GetTargetSize(&w, &h);
-
-                // Calculate page size i.e. number of scroll units you get on the
-                // current client window
-                int noPagePositions = w/m_xScrollPixelsPerLine;
-                if (noPagePositions < 1) noPagePositions = 1;
-                *xx = x - ((m_xScrollLines - noPagePositions - m_xScrollPosition) * m_xScrollPixelsPerLine);
-            }
-            else
-#endif
-            {
-                *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
-            }
-        }
-    }
+        *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
     if ( yy )
         *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine;
 }
@@ -970,33 +1006,7 @@ void wxScrollHelper::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) cons
 void wxScrollHelper::DoCalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
 {
     if ( xx )
-    {
-        if ((m_xScrollLines == 0) || (m_xScrollPixelsPerLine == 0))
-        {
-            // nothing to do
-            *xx = x;
-        }
-        else
-        {
-#ifdef __WXGTK__
-            if (m_win->GetLayoutDirection() == wxLayout_RightToLeft)
-            {
-                int w = 0, h = 0;
-                GetTargetSize(&w, &h);
-
-                // Calculate page size i.e. number of scroll units you get on the
-                // current client window
-                int noPagePositions = w/m_xScrollPixelsPerLine;
-                if (noPagePositions < 1) noPagePositions = 1;
-                *xx = x + ((m_xScrollLines - noPagePositions - m_xScrollPosition) * m_xScrollPixelsPerLine);
-            }
-            else
-#endif
-            {
-                *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine;
-            }
-        }
-    }
+        *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine;
     if ( yy )
         *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine;
 }
@@ -1178,18 +1188,18 @@ void wxScrollHelper::HandleOnChar(wxKeyEvent& event)
 
     if ( m_xScrollPosition != xScrollOld )
     {
-        wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_xScrollPosition,
+        wxScrollWinEvent evt(wxEVT_SCROLLWIN_THUMBTRACK, m_xScrollPosition,
                                wxHORIZONTAL);
-        event.SetEventObject(m_win);
-        m_win->GetEventHandler()->ProcessEvent(event);
+        evt.SetEventObject(m_win);
+        m_win->GetEventHandler()->ProcessEvent(evt);
     }
 
     if ( m_yScrollPosition != yScrollOld )
     {
-        wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_yScrollPosition,
+        wxScrollWinEvent evt(wxEVT_SCROLLWIN_THUMBTRACK, m_yScrollPosition,
                                wxVERTICAL);
-        event.SetEventObject(m_win);
-        m_win->GetEventHandler()->ProcessEvent(event);
+        evt.SetEventObject(m_win);
+        m_win->GetEventHandler()->ProcessEvent(evt);
     }
 }
 
@@ -1306,7 +1316,7 @@ void wxScrollHelper::HandleOnMouseWheel(wxMouseEvent& event)
         wxScrollWinEvent newEvent;
 
         newEvent.SetPosition(0);
-        newEvent.SetOrientation(wxVERTICAL);
+        newEvent.SetOrientation( event.GetWheelAxis() == 0 ? wxVERTICAL : wxHORIZONTAL);
         newEvent.SetEventObject(m_win);
 
         if (event.IsPageScroll())
@@ -1357,7 +1367,13 @@ bool wxScrolledWindow::Create(wxWindow *parent,
     MacSetClipChildren( true ) ;
 #endif
 
-    bool ok = wxPanel::Create(parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
+    // by default, we're scrollable in both directions (but if one of the
+    // styles is specified explicitly, we shouldn't add the other one
+    // automatically)
+    if ( !(style & (wxHSCROLL | wxVSCROLL)) )
+        style |= wxHSCROLL | wxVSCROLL;
+
+    bool ok = wxPanel::Create(parent, id, pos, size, style, name);
 
     return ok;
 }