]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/spinbutt.cpp
first pass of wxUniv merge - nothing works, most parts don't even compile
[wxWidgets.git] / src / univ / spinbutt.cpp
diff --git a/src/univ/spinbutt.cpp b/src/univ/spinbutt.cpp
new file mode 100644 (file)
index 0000000..b03ff3c
--- /dev/null
@@ -0,0 +1,433 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        univ/spinbutt.cpp
+// Purpose:     implementation of the universal version of wxSpinButton
+// Author:      Vadim Zeitlin
+// Modified by:
+// Created:     21.01.01
+// RCS-ID:      $Id$
+// Copyright:   (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+    #pragma implementation "spinbutbase.h"
+    #pragma implementation "univspinbutt.h"
+#endif
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#endif
+
+#include "wx/spinbutt.h"
+
+#if wxUSE_SPINBTN
+
+#include "wx/univ/renderer.h"
+#include "wx/univ/inphand.h"
+#include "wx/univ/theme.h"
+
+// ============================================================================
+// implementation of wxSpinButton
+// ============================================================================
+
+IMPLEMENT_DYNAMIC_CLASS(wxSpinEvent, wxNotifyEvent)
+IMPLEMENT_DYNAMIC_CLASS(wxSpinButton, wxControl)
+
+// ----------------------------------------------------------------------------
+// creation
+// ----------------------------------------------------------------------------
+
+#ifdef __VISUALC__
+    // warning C4355: 'this' : used in base member initializer list
+    #pragma warning(disable:4355)  // so what? disable it...
+#endif
+
+wxSpinButton::wxSpinButton()
+            : m_arrows(this)
+{
+    Init();
+}
+
+wxSpinButton::wxSpinButton(wxWindow *parent,
+                           wxWindowID id,
+                           const wxPoint& pos,
+                           const wxSize& size,
+                           long style,
+                           const wxString& name)
+            : m_arrows(this)
+{
+    Init();
+
+    (void)Create(parent, id, pos, size, style, name);
+}
+
+#ifdef __VISUALC__
+    // warning C4355: 'this' : used in base member initializer list
+    #pragma warning(default:4355)
+#endif
+
+void wxSpinButton::Init()
+{
+    for ( size_t n = 0; n < WXSIZEOF(m_arrowsState); n++ )
+    {
+        m_arrowsState[n] = 0;
+    }
+
+    m_value = 0;
+}
+
+bool wxSpinButton::Create(wxWindow *parent,
+                          wxWindowID id,
+                          const wxPoint& pos,
+                          const wxSize& size,
+                          long style,
+                          const wxString& name)
+{
+    // the spin buttons never have the border
+    style &= ~wxBORDER_MASK;
+
+    if ( !wxSpinButtonBase::Create(parent, id, pos, size, style,
+                                   wxDefaultValidator, name) )
+        return FALSE;
+
+    SetBestSize(size);
+
+    CreateInputHandler(wxINP_HANDLER_SPINBTN);
+
+    return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// value access
+// ----------------------------------------------------------------------------
+
+void wxSpinButton::SetRange(int minVal, int maxVal)
+{
+    wxSpinButtonBase::SetRange(minVal, maxVal);
+
+    // because the arrows disabled state might have changed - we don't check if
+    // it really changed or not because SetRange() is called rarely enough and
+    // son an extre refresh here doesn't really hurt
+    Refresh();
+}
+
+int wxSpinButton::GetValue() const
+{
+    return m_value;
+}
+
+void wxSpinButton::SetValue(int val)
+{
+    if ( val != m_value )
+    {
+        m_value = val;
+
+        Refresh();
+    }
+}
+
+int wxSpinButton::NormalizeValue(int value) const
+{
+    if ( value > m_max )
+    {
+        if ( GetWindowStyleFlag() & wxSP_WRAP )
+            value = m_min + (value - m_max) % (m_max - m_min);
+        else
+            value = m_max;
+    }
+    else if ( value < m_min )
+    {
+        if ( GetWindowStyleFlag() & wxSP_WRAP )
+            value = m_max - (m_min - value) % (m_max - m_min);
+        else
+            value = m_min;
+    }
+
+    return value;
+}
+
+bool wxSpinButton::ChangeValue(int inc)
+{
+    int valueNew = NormalizeValue(m_value + inc);
+
+    if ( valueNew == m_value )
+    {
+        // nothing changed - most likely because we are already at min/max
+        // value
+        return FALSE;
+    }
+
+    wxSpinEvent event(inc > 0 ? wxEVT_SCROLL_LINEUP : wxEVT_SCROLL_LINEDOWN,
+                      GetId());
+    event.SetPosition(valueNew);
+    event.SetEventObject(this);
+
+    if ( GetEventHandler()->ProcessEvent(event) && !event.IsAllowed() )
+    {
+        // programm has vetoed the event
+        return FALSE;
+    }
+
+    m_value = valueNew;
+
+    // send wxEVT_SCROLL_THUMBTRACK as well
+    event.SetEventType(wxEVT_SCROLL_THUMBTRACK);
+    (void)GetEventHandler()->ProcessEvent(event);
+
+    return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// size calculations
+// ----------------------------------------------------------------------------
+
+wxSize wxSpinButton::DoGetBestClientSize() const
+{
+    // a spin button has by default the same size as two scrollbar arrows put
+    // together
+    wxSize size = m_renderer->GetScrollbarArrowSize();
+    if ( IsVertical() )
+    {
+        size.y *= 2;
+    }
+    else
+    {
+        size.x *= 2;
+    }
+
+    return size;
+}
+
+// ----------------------------------------------------------------------------
+// wxControlWithArrows methods
+// ----------------------------------------------------------------------------
+
+int wxSpinButton::GetArrowState(wxScrollArrows::Arrow arrow) const
+{
+    int state = m_arrowsState[arrow];
+
+    // the arrow may also be disabled: either because the control is completely
+    // disabled
+    bool disabled = !IsEnabled();
+
+    if ( !disabled && !(GetWindowStyleFlag() & wxSP_WRAP) )
+    {
+        // ... or because we can't go any further - note that this never
+        // happens if we just wrap
+        if ( IsVertical() )
+        {
+            if ( arrow == wxScrollArrows::Arrow_First )
+                disabled = m_value == m_max;
+            else
+                disabled = m_value == m_min;
+        }
+        else // horizontal
+        {
+            if ( arrow == wxScrollArrows::Arrow_First )
+                disabled = m_value == m_min;
+            else
+                disabled = m_value == m_max;
+        }
+    }
+
+    if ( disabled )
+    {
+        state |= wxCONTROL_DISABLED;
+    }
+
+    return state;
+}
+
+void wxSpinButton::SetArrowFlag(wxScrollArrows::Arrow arrow, int flag, bool set)
+{
+    int state = m_arrowsState[arrow];
+    if ( set )
+        state |= flag;
+    else
+        state &= ~flag;
+
+    if ( state != m_arrowsState[arrow] )
+    {
+        m_arrowsState[arrow] = state;
+        Refresh();
+    }
+}
+
+bool wxSpinButton::OnArrow(wxScrollArrows::Arrow arrow)
+{
+    int valueOld = GetValue();
+
+    wxControlAction action;
+    if ( arrow == wxScrollArrows::Arrow_First )
+        action = IsVertical() ? wxACTION_SPIN_INC : wxACTION_SPIN_DEC;
+    else
+        action = IsVertical() ? wxACTION_SPIN_DEC : wxACTION_SPIN_INC;
+
+    PerformAction(action);
+
+    // did we scroll to the end?
+    return GetValue() != valueOld;
+}
+
+// ----------------------------------------------------------------------------
+// drawing
+// ----------------------------------------------------------------------------
+
+void wxSpinButton::DoDraw(wxControlRenderer *renderer)
+{
+    wxRect rectArrow1, rectArrow2;
+    CalcArrowRects(&rectArrow1, &rectArrow2);
+
+    wxDC& dc = renderer->GetDC();
+    m_arrows.DrawArrow(wxScrollArrows::Arrow_First, dc, rectArrow1);
+    m_arrows.DrawArrow(wxScrollArrows::Arrow_Second, dc, rectArrow2);
+}
+
+// ----------------------------------------------------------------------------
+// geometry
+// ----------------------------------------------------------------------------
+
+void wxSpinButton::CalcArrowRects(wxRect *rect1, wxRect *rect2) const
+{
+    // calculate the rectangles for both arrows: note that normally the 2
+    // arrows are adjacent to each other but if the total control width/height
+    // is odd, we can have 1 pixel between them
+    wxRect rectTotal = GetClientRect();
+
+    *rect1 =
+    *rect2 = rectTotal;
+    if ( IsVertical() )
+    {
+        rect1->height /= 2;
+        rect2->height /= 2;
+
+        rect2->y += rect1->height;
+        if ( rectTotal.height % 2 )
+            rect2->y++;
+    }
+    else // horizontal
+    {
+        rect1->width /= 2;
+        rect2->width /= 2;
+
+        rect2->x += rect1->width;
+        if ( rectTotal.width % 2 )
+            rect2->x++;
+    }
+}
+
+wxScrollArrows::Arrow wxSpinButton::HitTest(const wxPoint& pt) const
+{
+    wxRect rectArrow1, rectArrow2;
+    CalcArrowRects(&rectArrow1, &rectArrow2);
+
+    if ( rectArrow1.Inside(pt) )
+        return wxScrollArrows::Arrow_First;
+    else if ( rectArrow2.Inside(pt) )
+        return wxScrollArrows::Arrow_Second;
+    else
+        return wxScrollArrows::Arrow_None;
+}
+
+// ----------------------------------------------------------------------------
+// input processing
+// ----------------------------------------------------------------------------
+
+bool wxSpinButton::PerformAction(const wxControlAction& action,
+                                 long numArg,
+                                 const wxString& strArg)
+{
+    if ( action == wxACTION_SPIN_INC )
+        ChangeValue(+1);
+    else if ( action == wxACTION_SPIN_DEC )
+        ChangeValue(-1);
+    else
+        return wxControl::PerformAction(action, numArg, strArg);
+
+    return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// wxStdSpinButtonInputHandler
+// ----------------------------------------------------------------------------
+
+wxStdSpinButtonInputHandler::
+wxStdSpinButtonInputHandler(wxInputHandler *inphand)
+    : wxStdInputHandler(inphand)
+{
+}
+
+bool wxStdSpinButtonInputHandler::HandleKey(wxControl *control,
+                                            const wxKeyEvent& event,
+                                            bool pressed)
+{
+    if ( pressed )
+    {
+        wxControlAction action;
+        switch ( event.GetKeyCode() )
+        {
+            case WXK_DOWN:
+            case WXK_RIGHT:
+                action = wxACTION_SPIN_DEC;
+                break;
+
+            case WXK_UP:
+            case WXK_LEFT:
+                action = wxACTION_SPIN_INC;
+                break;
+        }
+
+        if ( !!action )
+        {
+            control->PerformAction(action);
+
+            return TRUE;
+        }
+    }
+
+    return wxStdInputHandler::HandleKey(control, event, pressed);
+}
+
+bool wxStdSpinButtonInputHandler::HandleMouse(wxControl *control,
+                                              const wxMouseEvent& event)
+{
+    wxSpinButton *spinbtn = wxStaticCast(control, wxSpinButton);
+
+    if ( spinbtn->GetArrows().HandleMouse(event) )
+    {
+        // don't refresh, everything is already done
+        return FALSE;
+    }
+
+    return wxStdInputHandler::HandleMouse(control, event);
+}
+
+bool wxStdSpinButtonInputHandler::HandleMouseMove(wxControl *control,
+                                                  const wxMouseEvent& event)
+{
+    wxSpinButton *spinbtn = wxStaticCast(control, wxSpinButton);
+
+    if ( spinbtn->GetArrows().HandleMouseMove(event) )
+    {
+        // processed by the arrows
+        return FALSE;
+    }
+
+    return wxStdInputHandler::HandleMouseMove(control, event);
+}
+
+
+#endif // wxUSE_SPINBTN