This keyword is not expanded by Git which means it's not replaced with the correct revision value in the releases made using git-based scripts and it's confusing to have lines with unexpanded "$Id$" in the released files. As expanding them with Git is not that simple (it could be done with git archive and export-subst attribute) and there are not many benefits in having them in the first place, just remove all these lines. If nothing else, this will make an eventual transition to Git simpler. Closes #14487. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
433 lines
11 KiB
C++
433 lines
11 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/univ/spinbutt.cpp
|
|
// Purpose: implementation of the universal version of wxSpinButton
|
|
// Author: Vadim Zeitlin
|
|
// Modified by:
|
|
// Created: 21.01.01
|
|
// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
|
|
// Licence: wxWindows licence
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#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
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// 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;
|
|
|
|
SetInitialSize(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 - 1) % (m_max - m_min + 1);
|
|
else
|
|
value = m_max;
|
|
}
|
|
else if ( value < m_min )
|
|
{
|
|
if ( GetWindowStyleFlag() & wxSP_WRAP )
|
|
value = m_max - (m_min - value - 1) % (m_max - m_min + 1);
|
|
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::HitTestArrow(const wxPoint& pt) const
|
|
{
|
|
wxRect rectArrow1, rectArrow2;
|
|
CalcArrowRects(&rectArrow1, &rectArrow2);
|
|
|
|
if ( rectArrow1.Contains(pt) )
|
|
return wxScrollArrows::Arrow_First;
|
|
else if ( rectArrow2.Contains(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;
|
|
}
|
|
|
|
/* static */
|
|
wxInputHandler *wxSpinButton::GetStdInputHandler(wxInputHandler *handlerDef)
|
|
{
|
|
static wxStdSpinButtonInputHandler s_handler(handlerDef);
|
|
|
|
return &s_handler;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxStdSpinButtonInputHandler
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxStdSpinButtonInputHandler::
|
|
wxStdSpinButtonInputHandler(wxInputHandler *inphand)
|
|
: wxStdInputHandler(inphand)
|
|
{
|
|
}
|
|
|
|
bool wxStdSpinButtonInputHandler::HandleKey(wxInputConsumer *consumer,
|
|
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.IsEmpty() )
|
|
{
|
|
consumer->PerformAction(action);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return wxStdInputHandler::HandleKey(consumer, event, pressed);
|
|
}
|
|
|
|
bool wxStdSpinButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
|
|
const wxMouseEvent& event)
|
|
{
|
|
wxSpinButton *spinbtn = wxStaticCast(consumer->GetInputWindow(), wxSpinButton);
|
|
|
|
if ( spinbtn->GetArrows().HandleMouse(event) )
|
|
{
|
|
// don't refresh, everything is already done
|
|
return false;
|
|
}
|
|
|
|
return wxStdInputHandler::HandleMouse(consumer, event);
|
|
}
|
|
|
|
bool wxStdSpinButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
|
|
const wxMouseEvent& event)
|
|
{
|
|
wxSpinButton *spinbtn = wxStaticCast(consumer->GetInputWindow(), wxSpinButton);
|
|
|
|
if ( spinbtn->GetArrows().HandleMouseMove(event) )
|
|
{
|
|
// processed by the arrows
|
|
return false;
|
|
}
|
|
|
|
return wxStdInputHandler::HandleMouseMove(consumer, event);
|
|
}
|
|
|
|
|
|
#endif // wxUSE_SPINBTN
|