slider.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,039 行 · 第 1/2 页

CPP
1,039
字号
///////////////////////////////////////////////////////////////////////////////
// Name:        univ/slider.cpp
// Purpose:     implementation of the universal version of wxSlider
// Author:      Vadim Zeitlin
// Modified by:
// Created:     09.02.01
// RCS-ID:      $Id: slider.cpp,v 1.17 2005/08/24 06:32:56 ABX Exp $
// Copyright:   (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
// Licence:     wxWindows licence
///////////////////////////////////////////////////////////////////////////////

/*
   There is some discrepancy in wxSL_LABELS style handling between wxMSW and
   wxGTK: the latter handles it natively and shows only the current value of
   the slider on the side corresponding to wxSL_TOP/BOTTOM/LEFT/RIGHT style
   given (which can be combined with wxSL_HORIZONTAL/VERTICAL) while wxMSW
   emulates this somehow and shows the min and max values near the ends of the
   slider and the current value in a separate static box nearby.

   We currently follow wxGTK except that wxSL_HORIZONTAL slider can only have
   the label displayed on top or bottom of it and wxSL_VERTICAL - to the left
   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 nothing at all, the current value only
   or the value and the limits - the current approach is just that of the
   lowest common denominator.

   TODO:

  +0. add ticks support
   1. support for all orientations
   2. draw the slider thumb highlighted when it is dragged
  ?3. manual ticks support?
 */

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
    #pragma implementation "univslider.h"
#endif

#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/dc.h"
#endif

#include "wx/slider.h"

#if wxUSE_SLIDER

#include "wx/univ/renderer.h"
#include "wx/univ/inphand.h"
#include "wx/univ/theme.h"

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

// the margin between the slider and the label (FIXME: hardcoded)
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()

// ----------------------------------------------------------------------------
// wxSlider creation
// ----------------------------------------------------------------------------

#ifdef __VISUALC__
    // warning C4355: 'this' : used in base member initializer list
    #pragma warning(disable:4355)
#endif

wxSlider::wxSlider()
        : m_thumb(this)
{
    Init();
}

wxSlider::wxSlider(wxWindow *parent,
                   wxWindowID id,
                   int value, int minValue, int maxValue,
                   const wxPoint& pos,
                   const wxSize& size,
                   long style,
                   const wxValidator& validator,
                   const wxString& name)
        : m_thumb(this)
{
    Init();

    (void)Create(parent, id, value, minValue, maxValue,
                 pos, size, style, validator, name);
}

#ifdef __VISUALC__
    // warning C4355: 'this' : used in base member initializer list
    #pragma warning(default:4355)
#endif

void wxSlider::Init()
{
    m_min =
    m_max =
    m_value = 0;

    m_tickFreq = 1;

    m_lineSize =
    m_pageSize = 0;

    m_thumbSize = 0;
    m_thumbFlags = 0;
}

bool wxSlider::Create(wxWindow *parent,
                      wxWindowID id,
                      int value, int minValue, int maxValue,
                      const wxPoint& pos,
                      const wxSize& size,
                      long style,
                      const wxValidator& validator,
                      const wxString& name)
{
    if ( !wxSliderBase::Create(parent, id, pos, size, style,
                               validator, name) )
        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);

    CreateInputHandler(wxINP_HANDLER_SLIDER);

    return true;
}

// ----------------------------------------------------------------------------
// wxSlider range and value
// ----------------------------------------------------------------------------

int wxSlider::GetValue() const
{
    return m_value;
}

int wxSlider::NormalizeValue(int value) const
{
    if ( value < m_min )
        return m_min;
    else if ( value > m_max )
        return m_max;
    else
        return value;
}

bool wxSlider::ChangeValueBy(int inc)
{
    return ChangeValueTo(NormalizeValue(m_value + inc));
}

bool wxSlider::ChangeValueTo(int value)
{
    // check if the value is going to change at all
    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") );

    m_value = value;

    Refresh();

    // generate the event
    wxCommandEvent event(wxEVT_COMMAND_SLIDER_UPDATED, GetId());
    event.SetInt(m_value);
    event.SetEventObject(this);

    (void)GetEventHandler()->ProcessEvent(event);

    return true;
}

void wxSlider::SetValue(int value)
{
    value = NormalizeValue(value);

    if ( m_value != value )
    {
        m_value = value;

        Refresh();
    }
}

void wxSlider::SetRange(int minValue, int maxValue)
{
    if ( minValue > maxValue )
    {
        // swap them, we always want min to be less than max
        int tmp = minValue;
        minValue = maxValue;
        maxValue = tmp;
    }

    if ( m_min != minValue || m_max != maxValue )
    {
        m_min = minValue;
        m_max = maxValue;

        // reset the value to make sure it is in the new range
        SetValue(m_value);

        // the size of the label rect might have changed
        if ( HasLabels() )
        {
            CalcGeometry();
        }

        Refresh();
    }
    //else: nothing changed
}

int wxSlider::GetMin() const
{
    return m_min;
}

int wxSlider::GetMax() const
{
    return m_max;
}

// ----------------------------------------------------------------------------
// wxSlider line/page/thumb size
// ----------------------------------------------------------------------------

void wxSlider::SetLineSize(int lineSize)
{
    wxCHECK_RET( lineSize >= 0, _T("invalid slider line size") );

    m_lineSize = lineSize;
}

void wxSlider::SetPageSize(int pageSize)
{
    wxCHECK_RET( pageSize >= 0, _T("invalid slider page size") );

    m_pageSize = pageSize;
}

int wxSlider::GetLineSize() const
{
    if ( !m_lineSize )
    {
        // the default line increment is 1
        wxConstCast(this, wxSlider)->m_lineSize = 1;
    }

    return m_lineSize;
}

int wxSlider::GetPageSize() const
{
    if ( !m_pageSize )
    {
        // the default page increment is m_tickFreq
        wxConstCast(this, wxSlider)->m_pageSize = m_tickFreq;
    }

    return m_pageSize;
}

void wxSlider::SetThumbLength(int lenPixels)
{
    wxCHECK_RET( lenPixels >= 0, _T("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
    if ( lenPixels != m_thumbSize )
    {
        m_thumbSize = lenPixels;

        Refresh();
    }
}

int wxSlider::GetThumbLength() const
{
    wxSize sz = GetDefaultThumbSize();
    int len = (IsVert() ? sz.x : sz.y);
    if (m_thumbSize > len)
    {
        return m_thumbSize;
    }
    else
    {
        return len;
    }

}

// ----------------------------------------------------------------------------
// wxSlider ticks
// ----------------------------------------------------------------------------

void wxSlider::SetTickFreq(int n, int WXUNUSED(dummy))
{
    wxCHECK_RET (n > 0, _T("invalid slider tick frequency"));

    if ( n != m_tickFreq )
    {
        m_tickFreq = n;

        Refresh();
    }
}

// ----------------------------------------------------------------------------
// wxSlider geometry
// ----------------------------------------------------------------------------

wxSize wxSlider::CalcLabelSize() const
{
    wxSize size;

    // 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") );

    wxCoord w1, h1, w2, h2;
    GetTextExtent(FormatValue(m_min), &w1, &h1);
    GetTextExtent(FormatValue(m_max), &w2, &h2);

    size.x = wxMax(w1, w2);
    size.y = wxMax(h1, h2);

    return size;
}

wxSize wxSlider::DoGetBestClientSize() const
{
    // this dimension is completely arbitrary
    static const wxCoord SLIDER_WIDTH = 40;

    long style = GetWindowStyle();

    // first calculate the size of the slider itself: i.e. the shaft and the
    // thumb
    wxCoord height = GetRenderer()->GetSliderDim();

    wxSize size;
    if ( IsVert() )
    {
        size.x = height;
        size.y = SLIDER_WIDTH;
    }
    else // horizontal
    {
        size.x = SLIDER_WIDTH;
        size.y = height;
    }

    // add space for ticks
    if ( HasTicks() )
    {
        wxCoord lenTick = GetRenderer()->GetSliderTickLen();
        if (style & wxSL_BOTH)
        {
            lenTick = 2 * lenTick;
        }

        if ( IsVert() )
            size.x += lenTick;
        else
            size.y += lenTick;
    }

    // if we have the label, reserve enough space for it
    if ( HasLabels() )
    {
        wxSize sizeLabels = CalcLabelSize();

        if (style & (wxSL_LEFT|wxSL_RIGHT))
        {
            size.x += sizeLabels.x + SLIDER_LABEL_MARGIN;
        }
        else if (style & (wxSL_TOP|wxSL_BOTTOM))
        {
            size.y += sizeLabels.y + SLIDER_LABEL_MARGIN;
        }
    }

    return size;
}

void wxSlider::OnSize(wxSizeEvent& event)
{
    CalcGeometry();

    event.Skip();
}

const wxRect& wxSlider::GetSliderRect() const
{
    if ( m_rectSlider.width < 0 )
    {
        wxConstCast(this, wxSlider)->CalcGeometry();
    }

    return m_rectSlider;
}

void wxSlider::CalcGeometry()
{
    /*
       recalc the label and slider positions, this looks like this for
       wxSL_HORIZONTAL | wxSL_TOP slider:

       LLL             lll
       -------------------------
       |                T      |  <-- this is the slider rect
       | HHHHHHHHHHHHHHHTHHHHH |
       |                T      |
       | *  *  *  *  *  *  *  *|
       -------------------------

       LLL is m_rectLabel as calculated here and lll is the real rect used for
       label drawing in OnDraw() (TTT indicated the thumb position and *s are
       the ticks)

       in the wxSL_VERTICAL | wxSL_RIGHT case the picture is like this:

       ------ LLL
       | H  |
       | H *|
       | H  |
       | H *|
       | H  |
       | H *|
       | H  |
       |TTT*| lll
       | H  |
       | H *|
       ------
    */
    long style = GetWindowStyle();

    // initialize to the full client rect
    wxRect rectTotal = GetClientRect();
    m_rectSlider = rectTotal;
    wxSize sizeThumb = GetThumbSize();

    // Labels reduce the size of the slider rect
    if ( HasLabels() )
    {
       wxSize sizeLabels = CalcLabelSize();

        m_rectLabel = wxRect(rectTotal.GetPosition(), sizeLabels);

        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)
        {
            // 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)
        {
            // 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)
        {
            // shrink the slider and move the label to the right
            m_rectSlider.width -= sizeLabels.x + SLIDER_LABEL_MARGIN;
            m_rectLabel.x += m_rectSlider.width + SLIDER_LABEL_MARGIN;
        }
    }

    // calculate ticks too
    if ( HasTicks() )
    {
        wxCoord lenTick = GetRenderer()->GetSliderTickLen();

        // it
        m_rectTicks = GetShaftRect();

        if ( IsVert() )
        {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?