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 + -
显示快捷键?