X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/aeb313f31c44c769c1749d945c7829787ee4c884..1e6feb95a79834836e88143b15d9f424ebe79621:/src/univ/spinbutt.cpp diff --git a/src/univ/spinbutt.cpp b/src/univ/spinbutt.cpp new file mode 100644 index 0000000000..b03ff3c0a4 --- /dev/null +++ b/src/univ/spinbutt.cpp @@ -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 +// 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