]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/slider.cpp
Fix crash in wxStaticBox::HandleEraseBkgnd() in wxMSW on closing.
[wxWidgets.git] / src / univ / slider.cpp
index adfa70db53dce77cec466cb10e09ecb19eda80cc..dde77642183f5314e7f57dda3764f0ab9a44b6a1 100644 (file)
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////////
-// Name:        univ/slider.cpp
+// Name:        src/univ/slider.cpp
 // Purpose:     implementation of the universal version of wxSlider
 // Author:      Vadim Zeitlin
 // Modified by:
@@ -22,9 +22,9 @@
    or right.
 
    What we really need is probably a more fine grain control on labels, i.e. we
-   should be able to select if we show nothign at all, the current value only
+   should be able to select if we show nothing at all, the current value only
    or the value and the limits - the current approach is just that of the
-   greatest common denominator.
+   lowest common denominator.
 
    TODO:
 
 // headers
 // ----------------------------------------------------------------------------
 
-#ifdef __GNUG__
-    #pragma implementation "univslider.h"
-#endif
-
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
     #pragma hdrstop
 #endif
 
-#ifndef WX_PRECOMP
-    #include "wx/dc.h"
-#endif
+#if wxUSE_SLIDER
 
 #include "wx/slider.h"
 
-#if wxUSE_SLIDER
+#ifndef WX_PRECOMP
+    #include "wx/dc.h"
+#endif
 
 #include "wx/univ/renderer.h"
 #include "wx/univ/inphand.h"
 #include "wx/univ/theme.h"
 
+// ----------------------------------------------------------------------------
+// wxStdSliderInputHandler: default slider input handling
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxStdSliderInputHandler : public wxStdInputHandler
+{
+public:
+    // default ctor
+    wxStdSliderInputHandler(wxInputHandler *inphand)
+        : wxStdInputHandler(inphand)
+    {
+    }
+
+    // base class methods
+    virtual bool HandleKey(wxInputConsumer *consumer,
+                           const wxKeyEvent& event,
+                           bool pressed);
+    virtual bool HandleMouse(wxInputConsumer *consumer,
+                             const wxMouseEvent& event);
+    virtual bool HandleMouseMove(wxInputConsumer *consumer,
+                                 const wxMouseEvent& event);
+
+    virtual bool HandleFocus(wxInputConsumer *consumer, const wxFocusEvent& event);
+};
+
 // ----------------------------------------------------------------------------
 // constants
 // ----------------------------------------------------------------------------
@@ -75,8 +96,6 @@ static const wxCoord SLIDER_LABEL_MARGIN = 2;
 // implementation of wxSlider
 // ============================================================================
 
-IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl)
-
 BEGIN_EVENT_TABLE(wxSlider, wxControl)
     EVT_SIZE(wxSlider::OnSize)
 END_EVENT_TABLE()
@@ -143,18 +162,18 @@ bool wxSlider::Create(wxWindow *parent,
 {
     if ( !wxSliderBase::Create(parent, id, pos, size, style,
                                validator, name) )
-        return FALSE;
+        return false;
 
     SetRange(minValue, maxValue);
     SetValue(value);
 
     // call this after setting the range as the best size depends (at least if
     // we have wxSL_LABELS style) on the range
-    SetBestSize(size);
+    SetInitialSize(size);
 
     CreateInputHandler(wxINP_HANDLER_SLIDER);
 
-    return TRUE;
+    return true;
 }
 
 // ----------------------------------------------------------------------------
@@ -184,24 +203,29 @@ bool wxSlider::ChangeValueBy(int inc)
 bool wxSlider::ChangeValueTo(int value)
 {
     // check if the value is going to change at all
-    if (value == m_value) return FALSE;
+    if (value == m_value)
+        return false;
 
     // this method is protected and we should only call it with normalized
     // value!
-    wxCHECK_MSG( IsInRange(value), FALSE, _T("invalid slider value") );
+    wxCHECK_MSG( IsInRange(value), false, wxT("invalid slider value") );
 
     m_value = value;
 
     Refresh();
 
-    // generate the event
+    // generate the events: both a specific scroll event and a command event
+    wxScrollEvent eventScroll(wxEVT_SCROLL_CHANGED, GetId());
+    eventScroll.SetPosition(m_value);
+    eventScroll.SetEventObject( this );
+    (void)GetEventHandler()->ProcessEvent(eventScroll);
+
     wxCommandEvent event(wxEVT_COMMAND_SLIDER_UPDATED, GetId());
     event.SetInt(m_value);
     event.SetEventObject(this);
-
     (void)GetEventHandler()->ProcessEvent(event);
 
-    return TRUE;
+    return true;
 }
 
 void wxSlider::SetValue(int value)
@@ -261,14 +285,14 @@ int wxSlider::GetMax() const
 
 void wxSlider::SetLineSize(int lineSize)
 {
-    wxCHECK_RET( lineSize >= 0, _T("invalid slider line size") );
+    wxCHECK_RET( lineSize >= 0, wxT("invalid slider line size") );
 
     m_lineSize = lineSize;
 }
 
 void wxSlider::SetPageSize(int pageSize)
 {
-    wxCHECK_RET( pageSize >= 0, _T("invalid slider page size") );
+    wxCHECK_RET( pageSize >= 0, wxT("invalid slider page size") );
 
     m_pageSize = pageSize;
 }
@@ -297,7 +321,7 @@ int wxSlider::GetPageSize() const
 
 void wxSlider::SetThumbLength(int lenPixels)
 {
-    wxCHECK_RET( lenPixels >= 0, _T("invalid slider thumb size") );
+    wxCHECK_RET( lenPixels >= 0, wxT("invalid slider thumb size") );
 
     // use m_thumbSize here directly and not GetThumbLength() to avoid setting
     // it to the default value as we don't need it
@@ -313,7 +337,7 @@ int wxSlider::GetThumbLength() const
 {
     wxSize sz = GetDefaultThumbSize();
     int len = (IsVert() ? sz.x : sz.y);
-    if (m_thumbSize > len) 
+    if (m_thumbSize > len)
     {
         return m_thumbSize;
     }
@@ -328,9 +352,9 @@ int wxSlider::GetThumbLength() const
 // wxSlider ticks
 // ----------------------------------------------------------------------------
 
-void wxSlider::SetTickFreq(int n, int WXUNUSED(dummy))
+void wxSlider::DoSetTickFreq(int n)
 {
-    wxCHECK_RET (n > 0, _T("invalid slider tick frequency"));
+    wxCHECK_RET (n > 0, wxT("invalid slider tick frequency"));
 
     if ( n != m_tickFreq )
     {
@@ -350,7 +374,7 @@ wxSize wxSlider::CalcLabelSize() const
 
     // there is no sense in trying to calc the labels size if we haven't got
     // any, the caller must check for it
-    wxCHECK_MSG( HasLabels(), size, _T("shouldn't be called") );
+    wxCHECK_MSG( HasLabels(), size, wxT("shouldn't be called") );
 
     wxCoord w1, h1, w2, h2;
     GetTextExtent(FormatValue(m_min), &w1, &h1);
@@ -389,7 +413,7 @@ wxSize wxSlider::DoGetBestClientSize() const
     if ( HasTicks() )
     {
         wxCoord lenTick = GetRenderer()->GetSliderTickLen();
-        if (style & wxSL_BOTH) 
+        if (style & wxSL_BOTH)
         {
             lenTick = 2 * lenTick;
         }
@@ -482,25 +506,25 @@ void wxSlider::CalcGeometry()
 
         m_rectLabel = wxRect(rectTotal.GetPosition(), sizeLabels);
 
-        if (style & wxSL_TOP) 
+        if (style & wxSL_TOP)
         {
             // shrink and offset the slider to the bottom
             m_rectSlider.y += sizeLabels.y + SLIDER_LABEL_MARGIN;
             m_rectSlider.height -= sizeLabels.y + SLIDER_LABEL_MARGIN;
         }
-        else if (style & wxSL_BOTTOM) 
+        else if (style & wxSL_BOTTOM)
         {
             // shrink the slider and move the label to the bottom
             m_rectSlider.height -= sizeLabels.y + SLIDER_LABEL_MARGIN;
             m_rectLabel.y += m_rectSlider.height + SLIDER_LABEL_MARGIN;
         }
-        else if (style & wxSL_LEFT) 
+        else if (style & wxSL_LEFT)
         {
             // shrink and offset the slider to the right
             m_rectSlider.x += sizeLabels.x + SLIDER_LABEL_MARGIN;
             m_rectSlider.width -= sizeLabels.x + SLIDER_LABEL_MARGIN;
         }
-        else if (style & wxSL_RIGHT) 
+        else if (style & wxSL_RIGHT)
         {
             // shrink the slider and move the label to the right
             m_rectSlider.width -= sizeLabels.x + SLIDER_LABEL_MARGIN;
@@ -518,7 +542,7 @@ void wxSlider::CalcGeometry()
 
         if ( IsVert() )
         {
-            if (style & (wxSL_LEFT|wxSL_BOTH)) 
+            if (style & (wxSL_LEFT|wxSL_BOTH))
             {
                 m_rectTicks.x = m_rectSlider.x;
             }
@@ -530,7 +554,7 @@ void wxSlider::CalcGeometry()
         }
         else // horizontal
         {
-            if (style & (wxSL_TOP|wxSL_BOTH)) 
+            if (style & (wxSL_TOP|wxSL_BOTH))
             {
                 m_rectTicks.y = m_rectSlider.y;
             }
@@ -599,8 +623,9 @@ void wxSlider::CalcThumbRect(const wxRect *rectShaftIn,
     }
 
     wxCoord lenShaft,
-            lenThumb,
-           *p;
+            lenThumb;
+    wxCoord *p;
+
     wxRect rectThumb(rectShaft.GetPosition(), GetThumbSize());
     if ( isVertical )
     {
@@ -663,7 +688,7 @@ void wxSlider::CalcThumbRect(const wxRect *rectShaftIn,
 
 wxString wxSlider::FormatValue(int value) const
 {
-    return wxString::Format(_T("%d"), value);
+    return wxString::Format(wxT("%d"), value);
 }
 
 void wxSlider::DoDraw(wxControlRenderer *renderer)
@@ -708,19 +733,19 @@ void wxSlider::DoDraw(wxControlRenderer *renderer)
     {
         // align it to be close to the shaft
         int align = 0;
-        if (style & wxSL_TOP) 
+        if (style & wxSL_TOP)
         {
             align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_TOP;
         }
-        else if (style & wxSL_BOTTOM) 
+        else if (style & wxSL_BOTTOM)
         {
             align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_BOTTOM;
         }
-        else if (style & wxSL_LEFT) 
+        else if (style & wxSL_LEFT)
         {
             align = wxALIGN_CENTRE_VERTICAL|wxALIGN_LEFT;
         }
-        else if (style & wxSL_RIGHT) 
+        else if (style & wxSL_RIGHT)
         {
             align = wxALIGN_CENTRE_VERTICAL|wxALIGN_RIGHT;
         }
@@ -742,50 +767,89 @@ bool wxSlider::PerformAction(const wxControlAction& action,
                              long numArg,
                              const wxString& strArg)
 {
-     if ( action == wxACTION_SLIDER_START )
+    wxEventType scrollEvent = wxEVT_NULL;
+    int value;
+    bool valueChanged = true;
+
+    if ( action == wxACTION_SLIDER_START )
     {
-        ChangeValueTo(m_min);
+        scrollEvent = wxEVT_SCROLL_TOP;
+        value = m_min;
     }
     else if ( action == wxACTION_SLIDER_END )
     {
-        ChangeValueTo(m_max);
+        scrollEvent = wxEVT_SCROLL_BOTTOM;
+        value = m_max;
     }
     else if ( action == wxACTION_SLIDER_PAGE_CHANGE )
     {
-        ChangeValueBy(numArg * GetPageSize());
+        value = NormalizeValue(m_value + numArg * GetPageSize());
     }
     else if ( action == wxACTION_SLIDER_LINE_UP )
     {
-        ChangeValueBy(+GetLineSize());
+        scrollEvent = wxEVT_SCROLL_LINEUP;
+        value = NormalizeValue(m_value + +GetLineSize());
     }
     else if ( action == wxACTION_SLIDER_LINE_DOWN )
     {
-        ChangeValueBy(-GetLineSize());
+        scrollEvent = wxEVT_SCROLL_LINEDOWN;
+        value = NormalizeValue(m_value + -GetLineSize());
     }
     else if ( action == wxACTION_SLIDER_PAGE_UP )
     {
-        ChangeValueBy(+GetPageSize());
+        scrollEvent = wxEVT_SCROLL_PAGEUP;
+        value = NormalizeValue(m_value + +GetPageSize());
     }
     else if ( action == wxACTION_SLIDER_PAGE_DOWN )
     {
-        ChangeValueBy(-GetPageSize());
+        scrollEvent = wxEVT_SCROLL_PAGEDOWN;
+        value = NormalizeValue(m_value + -GetPageSize());
     }
-    else if ( action == wxACTION_SLIDER_THUMB_DRAG )
+    else if ( action == wxACTION_SLIDER_THUMB_DRAG ||
+                action == wxACTION_SLIDER_THUMB_MOVE )
     {
-        // no special processing for it
-        return TRUE;
+        scrollEvent = wxEVT_SCROLL_THUMBTRACK;
+
+        // we shouldn't generate a command event about this change but we still
+        // should update our value and the slider appearance
+        valueChanged = false;
+        m_value =
+        value = (int)numArg;
+        Refresh();
     }
-    else if ( action == wxACTION_SLIDER_THUMB_MOVE ||
-              action == wxACTION_SLIDER_THUMB_RELEASE )
+    else if ( action == wxACTION_SLIDER_THUMB_RELEASE )
     {
-        ChangeValueTo((int)numArg);
+        scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
+        value = (int)numArg;
     }
     else
     {
         return wxControl::PerformAction(action, numArg, strArg);
     }
 
-    return TRUE;
+    // update wxSlider current value and generate wxCommandEvent, except while
+    // dragging the thumb
+    if ( valueChanged )
+        ChangeValueTo(value);
+
+    // also generate more precise wxScrollEvent if applicable
+    if ( scrollEvent != wxEVT_NULL )
+    {
+        wxScrollEvent event(scrollEvent, GetId());
+        event.SetPosition(value);
+        event.SetEventObject( this );
+        GetEventHandler()->ProcessEvent(event);
+    }
+
+    return true;
+}
+
+/* static */
+wxInputHandler *wxSlider::GetStdInputHandler(wxInputHandler *handlerDef)
+{
+    static wxStdSliderInputHandler s_handler(handlerDef);
+
+    return &s_handler;
 }
 
 // ----------------------------------------------------------------------------
@@ -799,14 +863,14 @@ wxScrollThumb::Shaft wxSlider::HitTest(const wxPoint& pt) const
     CalcThumbRect(&rectShaft, &rectThumb, NULL);
 
     // check for possible shaft or thumb hit
-    if (!rectShaft.Inside(pt) && !rectThumb.Inside(pt)) 
+    if (!rectShaft.Contains(pt) && !rectThumb.Contains(pt))
     {
         return wxScrollThumb::Shaft_None;
     }
 
     // the position to test and the start and end of the thumb
     wxCoord x, x1, x2, x3, x4;
-    if (IsVert()) 
+    if (IsVert())
     {
         x = pt.y;
         x1 = rectThumb.GetBottom();
@@ -822,13 +886,13 @@ wxScrollThumb::Shaft wxSlider::HitTest(const wxPoint& pt) const
         x3 = rectThumb.GetRight();
         x4 = rectShaft.GetRight();
     }
-    if ((x1 <= x) & (x < x2)) 
+    if ((x1 <= x) && (x < x2))
     {
         // or to the left
         return wxScrollThumb::Shaft_Above;
     }
 
-    if ((x3 < x) & (x <= x4)) {
+    if ((x3 < x) && (x <= x4)) {
         // or to the right
         return wxScrollThumb::Shaft_Below;
     }
@@ -896,7 +960,7 @@ void wxSlider::SetShaftPartState(wxScrollThumb::Shaft shaftPart,
 
 void wxSlider::OnThumbDragStart(int pos)
 {
-    if (IsVert()) 
+    if (IsVert())
     {
         PerformAction(wxACTION_SLIDER_THUMB_DRAG, m_max - pos);
     }
@@ -908,7 +972,7 @@ void wxSlider::OnThumbDragStart(int pos)
 
 void wxSlider::OnThumbDrag(int pos)
 {
-    if (IsVert()) 
+    if (IsVert())
     {
         PerformAction(wxACTION_SLIDER_THUMB_MOVE, m_max - pos);
     }
@@ -920,7 +984,7 @@ void wxSlider::OnThumbDrag(int pos)
 
 void wxSlider::OnThumbDragEnd(int pos)
 {
-    if (IsVert()) 
+    if (IsVert())
     {
         PerformAction(wxACTION_SLIDER_THUMB_RELEASE, m_max - pos);
     }
@@ -944,14 +1008,14 @@ bool wxSlider::OnPageScroll(int pageInc)
 }
 
 // ----------------------------------------------------------------------------
-// wxStdSliderButtonInputHandler
+// wxStdSliderInputHandler
 // ----------------------------------------------------------------------------
 
-bool wxStdSliderButtonInputHandler::HandleKey(wxInputConsumer *consumer,
+bool wxStdSliderInputHandler::HandleKey(wxInputConsumer *consumer,
                                               const wxKeyEvent& event,
                                               bool pressed)
 {
-   if ( pressed )
+    if ( pressed )
     {
         int keycode = event.GetKeyCode();
 
@@ -976,29 +1040,27 @@ bool wxStdSliderButtonInputHandler::HandleKey(wxInputConsumer *consumer,
                 action = wxACTION_SLIDER_LINE_DOWN;
                 break;
 
-            case WXK_PRIOR:
             case WXK_PAGEUP:
                 action = wxACTION_SLIDER_PAGE_UP;
                 break;
 
-            case WXK_NEXT:
             case WXK_PAGEDOWN:
                 action = wxACTION_SLIDER_PAGE_DOWN;
                 break;
         }
 
-        if ( !!action )
+        if ( !action.IsEmpty() )
         {
             consumer->PerformAction(action);
 
-            return TRUE;
+            return true;
         }
     }
 
     return wxStdInputHandler::HandleKey(consumer, event, pressed);
 }
 
-bool wxStdSliderButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
+bool wxStdSliderInputHandler::HandleMouse(wxInputConsumer *consumer,
                                                 const wxMouseEvent& event)
 {
     wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
@@ -1006,13 +1068,13 @@ bool wxStdSliderButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
     if ( slider->GetThumb().HandleMouse(event) )
     {
         // processed by the thumb
-        return FALSE;
+        return false;
     }
 
     return wxStdInputHandler::HandleMouse(consumer, event);
 }
 
-bool wxStdSliderButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
+bool wxStdSliderInputHandler::HandleMouseMove(wxInputConsumer *consumer,
                                                     const wxMouseEvent& event)
 {
     wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
@@ -1020,17 +1082,18 @@ bool wxStdSliderButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
     if ( slider->GetThumb().HandleMouseMove(event) )
     {
         // processed by the thumb
-        return FALSE;
+        return false;
     }
 
     return wxStdInputHandler::HandleMouseMove(consumer, event);
 }
 
-bool wxStdSliderButtonInputHandler::HandleFocus(wxInputConsumer *consumer,
-                                                const wxFocusEvent& event)
+bool
+wxStdSliderInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
+                                           const wxFocusEvent& WXUNUSED(event))
 {
-    // slider's appearance changes when it gets/loses focus
-    return TRUE;
+    // slider appearance changes when it gets/loses focus
+    return true;
 }
 
 #endif // wxUSE_SLIDER