///////////////////////////////////////////////////////////////////////////////
-// Name: univ/slider.cpp
+// Name: src/univ/slider.cpp
// Purpose: implementation of the universal version of wxSlider
// Author: Vadim Zeitlin
// Modified by:
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 nothign at all, the current value only
+ 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
- greatest common denominator.
+ lowest common denominator.
TODO:
// headers
// ----------------------------------------------------------------------------
-#ifdef __GNUG__
- #pragma implementation "univslider.h"
-#endif
-
#include "wx/wxprec.h"
#ifdef __BORLANDC__
{
if ( !wxSliderBase::Create(parent, id, pos, size, style,
validator, name) )
- return FALSE;
+ return false;
SetRange(minValue, maxValue);
SetValue(value);
CreateInputHandler(wxINP_HANDLER_SLIDER);
- return TRUE;
+ return true;
}
// ----------------------------------------------------------------------------
bool wxSlider::ChangeValueTo(int value)
{
- // this method is protected and we should only call it with normalized
- // value!
- wxCHECK_MSG( IsInRange(value), FALSE, _T("invalid slider value") );
-
// check if the value is going to change at all
- if ( value == m_value )
- return FALSE;
+ if (value == m_value)
+ return false;
- // refresh the old thumb position
- RefreshThumb();
+ // 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;
- // and the new one
- RefreshThumb();
+ Refresh();
+
+ // generate the events: both a specific scroll event and a command event
+ wxScrollEvent eventScroll(wxEVT_SCROLL_CHANGED, GetId());
+ eventScroll.SetPosition(m_value);
+ eventScroll.SetEventObject( this );
+ (void)GetEventHandler()->ProcessEvent(eventScroll);
- // generate the event
wxCommandEvent event(wxEVT_COMMAND_SLIDER_UPDATED, GetId());
event.SetInt(m_value);
event.SetEventObject(this);
-
(void)GetEventHandler()->ProcessEvent(event);
- return TRUE;
+ return true;
}
void wxSlider::SetValue(int value)
void wxSlider::SetLineSize(int lineSize)
{
- wxCHECK_RET( lineSize > 0, _T("invalid slider line size") );
+ 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") );
+ wxCHECK_RET( pageSize >= 0, _T("invalid slider page size") );
m_pageSize = pageSize;
}
{
if ( !m_pageSize )
{
- // the default page increment is 1/10 of the range
- wxConstCast(this, wxSlider)->m_pageSize = (m_max - m_min) / 10;
+ // 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") );
+ 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
int wxSlider::GetThumbLength() const
{
- if ( !m_thumbSize )
+ wxSize sz = GetDefaultThumbSize();
+ int len = (IsVert() ? sz.x : sz.y);
+ if (m_thumbSize > len)
{
- wxSize sz = GetDefaultThumbSize();
- return IsVert() ? sz.y : sz.x;
+ return m_thumbSize;
+ }
+ else
+ {
+ return len;
}
- return m_thumbSize;
}
// ----------------------------------------------------------------------------
void wxSlider::SetTickFreq(int n, int WXUNUSED(dummy))
{
+ wxCHECK_RET (n > 0, _T("invalid slider tick frequency"));
+
if ( n != m_tickFreq )
{
m_tickFreq = n;
wxSize wxSlider::DoGetBestClientSize() const
{
// this dimension is completely arbitrary
- static const wxCoord SLIDER_WIDTH = 100;
+ static const wxCoord SLIDER_WIDTH = 40;
+
+ long style = GetWindowStyle();
// first calculate the size of the slider itself: i.e. the shaft and the
// thumb
if ( HasTicks() )
{
wxCoord lenTick = GetRenderer()->GetSliderTickLen();
+ if (style & wxSL_BOTH)
+ {
+ lenTick = 2 * lenTick;
+ }
if ( IsVert() )
size.x += lenTick;
{
wxSize sizeLabels = CalcLabelSize();
- if ( IsVert() )
+ if (style & (wxSL_LEFT|wxSL_RIGHT))
+ {
size.x += sizeLabels.x + SLIDER_LABEL_MARGIN;
- else
+ }
+ else if (style & (wxSL_TOP|wxSL_BOTTOM))
+ {
size.y += sizeLabels.y + SLIDER_LABEL_MARGIN;
+ }
}
return size;
| 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();
+ wxSize sizeLabels = CalcLabelSize();
- m_rectSlider = rectTotal;
m_rectLabel = wxRect(rectTotal.GetPosition(), sizeLabels);
- // split the rect
- if ( IsVert() )
+ if (style & wxSL_TOP)
{
- sizeLabels.x += SLIDER_LABEL_MARGIN;
-
- if ( GetWindowStyle() & wxSL_LEFT )
- {
- // shrink and offset the slider to the right
- m_rectSlider.x += sizeLabels.x;
- m_rectSlider.width -= sizeLabels.x;
- }
- else // wxSL_RIGHT
- {
- // just shrink the slider and move the label to the right
- m_rectSlider.width -= sizeLabels.x;
-
- m_rectLabel.x += m_rectSlider.width + SLIDER_LABEL_MARGIN;
- }
+ // 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 // horizontal
+ else if (style & wxSL_BOTTOM)
{
- // same logic as above but x/y are trasnposed
- sizeLabels.y += SLIDER_LABEL_MARGIN;
-
- if ( GetWindowStyle() & wxSL_TOP )
- {
- m_rectSlider.y += sizeLabels.y;
- m_rectSlider.height -= sizeLabels.y;
- }
- else // wxSL_BOTTOM
- {
- m_rectSlider.height -= sizeLabels.y;
-
- m_rectLabel.y += m_rectSlider.height + SLIDER_LABEL_MARGIN;
- }
+ // 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;
}
- }
- else // no labels
- {
- // the slider takes the whole client rect
- m_rectSlider = rectTotal;
}
- // now adjust for ticks too
+ // calculate ticks too
if ( HasTicks() )
{
wxCoord lenTick = GetRenderer()->GetSliderTickLen();
- if ( IsVert() )
- {
- m_rectSlider.width -= lenTick;
- }
- else // horizontal
- {
- m_rectSlider.height -= lenTick;
- }
-
- // note that we must compute m_rectSlider first as GetShaftRect() uses
// it
m_rectTicks = GetShaftRect();
if ( IsVert() )
{
- m_rectTicks.x = m_rectSlider.x + m_rectSlider.width;
+ if (style & (wxSL_LEFT|wxSL_BOTH))
+ {
+ m_rectTicks.x = m_rectSlider.x;
+ }
+ else
+ { // wxSL_RIGHT
+ m_rectTicks.x = m_rectSlider.x + m_rectSlider.width - lenTick;
+ }
m_rectTicks.width = lenTick;
}
else // horizontal
{
- m_rectTicks.y = m_rectSlider.y + m_rectSlider.height;
+ if (style & (wxSL_TOP|wxSL_BOTH))
+ {
+ m_rectTicks.y = m_rectSlider.y;
+ }
+ else
+ { // wxSL_BOTTOM
+ m_rectTicks.y = m_rectSlider.y + m_rectSlider.height - lenTick;
+ }
m_rectTicks.height = lenTick;
}
+ }
+ // slider is never smaller than thumb size unless rectTotal
+ if ( IsVert() )
+ {
+ wxCoord width = wxMin ( rectTotal.width, sizeThumb.x );
+ m_rectSlider.width = wxMax ( m_rectSlider.width, width );
+ }
+ else
+ {
+ wxCoord height = wxMin ( rectTotal.height, sizeThumb.y );
+ m_rectSlider.height = wxMax ( m_rectSlider.height, height );
}
}
wxSize wxSlider::GetDefaultThumbSize() const
{
- return GetRenderer()->GetSliderThumbSize(GetSliderRect(), GetOrientation());
+ // Default size has no styles (arrows)
+ return GetRenderer()->GetSliderThumbSize(GetSliderRect(), 0, GetOrientation());
}
wxSize wxSlider::GetThumbSize() const
{
- wxSize sizeThumb = GetDefaultThumbSize();
-
- // if we have our own thumb length (set by the user), use it instead of the
- // default value
- if ( m_thumbSize )
- {
- if ( IsVert() )
- sizeThumb.y = m_thumbSize;
- else
- sizeThumb.x = m_thumbSize;
- }
-
- return sizeThumb;
+ return GetRenderer()->GetSliderThumbSize(GetSliderRect(), m_thumbSize, GetOrientation());
}
// ----------------------------------------------------------------------------
wxRect wxSlider::GetShaftRect() const
{
- return GetRenderer()->GetSliderShaftRect(m_rectSlider, GetOrientation());
+ return GetRenderer()->GetSliderShaftRect(m_rectSlider, m_thumbSize, GetOrientation(), GetWindowStyle());
}
void wxSlider::CalcThumbRect(const wxRect *rectShaftIn,
}
wxCoord lenShaft,
- lenThumb,
- *p;
+ lenThumb;
+ wxCoord *p;
+
wxRect rectThumb(rectShaft.GetPosition(), GetThumbSize());
if ( isVertical )
{
// position is not at lenShaft but at lenShaft - thumbSize
if ( m_max != m_min )
{
- *p += ((lenShaft - lenThumb)*(value - m_min))/(m_max - m_min);
+ if ( isVertical )
+ {
+ *p += ((lenShaft - lenThumb)*(m_max - value))/(m_max - m_min);
+ }
+ else
+ { // horz
+ *p += ((lenShaft - lenThumb)*(value - m_min))/(m_max - m_min);
+ }
}
// calc the label rect
if ( HasLabels() && rectLabelOut )
{
+ long style = GetWindowStyle();
wxRect rectLabel = m_rectLabel;
// centre the label relatively to the thumb position
- if ( isVertical )
+ if (style & (wxSL_TOP|wxSL_BOTTOM))
{
- rectLabel.y =
- rectThumb.y + (rectThumb.height - m_rectLabel.height)/2;
+ rectLabel.x = rectThumb.x + (rectThumb.width - m_rectLabel.width)/2;
}
- else // horz
+ else if (style & (wxSL_LEFT|wxSL_RIGHT))
{
- rectLabel.x =
- rectThumb.x + (rectThumb.width - m_rectLabel.width)/2;
+ rectLabel.y = rectThumb.y + (rectThumb.height - m_rectLabel.height)/2;
}
*rectLabelOut = rectLabel;
}
if ( rectThumbOut )
+
*rectThumbOut = rectThumb;
}
wxDC& dc = renderer->GetDC();
wxRect rectUpdate = GetUpdateClientRect();
- bool isVertical = IsVert();
wxOrientation orient = GetOrientation();
int flags = GetStateFlags();
+ long style = GetWindowStyle();
+
+ wxSize sz = GetThumbSize();
+ int len = IsVert() ? sz.x : sz.y;
// first draw the shaft
- wxRect rectShaft = rend->GetSliderShaftRect(m_rectSlider, orient);
+ wxRect rectShaft = rend->GetSliderShaftRect(m_rectSlider, len, orient, style);
if ( rectUpdate.Intersects(rectShaft) )
{
- rend->DrawSliderShaft(dc, m_rectSlider, orient, flags);
+ rend->DrawSliderShaft(dc, m_rectSlider, len, orient, flags, style);
}
// calculate the thumb position in pixels and draw it
wxRect rectThumb, rectLabel;
CalcThumbRect(&rectShaft, &rectThumb, &rectLabel);
- if ( rectUpdate.Intersects(rectThumb) )
+ // then draw the ticks
+ if ( HasTicks() && rectUpdate.Intersects(m_rectTicks) )
{
- rend->DrawSliderThumb(dc, rectThumb, orient, flags | m_thumbFlags);
+ rend->DrawSliderTicks(dc, m_rectSlider, len, orient,
+ m_min, m_max, m_tickFreq, flags, style);
}
- // then draw the ticks
- if ( HasTicks() && rectUpdate.Intersects(m_rectTicks) )
+ // then draw the thumb
+ if ( rectUpdate.Intersects(rectThumb) )
{
- rend->DrawSliderTicks(dc, m_rectTicks, rectThumb.GetSize(), orient,
- m_min, m_max, m_tickFreq);
+ rend->DrawSliderThumb(dc, rectThumb, orient, flags | m_thumbFlags, style);
}
// finally, draw the label near the thumb
if ( HasLabels() && rectUpdate.Intersects(rectLabel) )
{
// align it to be close to the shaft
- int align;
- if ( isVertical )
+ int align = 0;
+ if (style & wxSL_TOP)
{
- align = wxALIGN_CENTRE_VERTICAL |
- (GetWindowStyle() & wxSL_RIGHT ? wxALIGN_LEFT
- : wxALIGN_RIGHT);
+ align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_TOP;
}
- else // horz
+ else if (style & wxSL_BOTTOM)
{
- align = wxALIGN_CENTRE;
+ align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_BOTTOM;
+ }
+ else if (style & wxSL_LEFT)
+ {
+ align = wxALIGN_CENTRE_VERTICAL|wxALIGN_LEFT;
+ }
+ else if (style & wxSL_RIGHT)
+ {
+ align = wxALIGN_CENTRE_VERTICAL|wxALIGN_RIGHT;
}
dc.SetFont(GetFont());
}
}
-void wxSlider::RefreshThumb()
-{
- wxRect rectThumb, rectLabel;
- CalcThumbRect(NULL, &rectThumb, &rectLabel);
-
- Refresh(TRUE /* erase background */, &rectThumb);
- if ( HasLabels() )
- {
- Refresh(TRUE, &rectLabel);
- }
-}
-
// ----------------------------------------------------------------------------
// wxSlider input processing
// ----------------------------------------------------------------------------
long numArg,
const wxString& strArg)
{
+ wxEventType scrollEvent = wxEVT_NULL;
+ int value;
+ bool valueChanged = true;
+
if ( action == wxACTION_SLIDER_START )
{
- ChangeValueTo(m_min);
+ scrollEvent = wxEVT_SCROLL_TOP;
+ value = m_min;
}
else if ( action == wxACTION_SLIDER_END )
{
- ChangeValueTo(m_max);
+ scrollEvent = wxEVT_SCROLL_BOTTOM;
+ value = m_max;
}
else if ( action == wxACTION_SLIDER_PAGE_CHANGE )
{
- ChangeValueBy(numArg * GetPageSize());
+ value = NormalizeValue(m_value + numArg * GetPageSize());
}
else if ( action == wxACTION_SLIDER_LINE_UP )
{
- ChangeValueBy(-GetLineSize());
+ scrollEvent = wxEVT_SCROLL_LINEUP;
+ value = NormalizeValue(m_value + +GetLineSize());
}
- else if ( action == wxACTION_SLIDER_PAGE_UP )
+ else if ( action == wxACTION_SLIDER_LINE_DOWN )
{
- return PerformAction(wxACTION_SLIDER_PAGE_CHANGE, -1);
+ scrollEvent = wxEVT_SCROLL_LINEDOWN;
+ value = NormalizeValue(m_value + -GetLineSize());
}
- else if ( action == wxACTION_SLIDER_LINE_DOWN )
+ else if ( action == wxACTION_SLIDER_PAGE_UP )
{
- ChangeValueBy(GetLineSize());
+ scrollEvent = wxEVT_SCROLL_PAGEUP;
+ value = NormalizeValue(m_value + +GetPageSize());
}
else if ( action == wxACTION_SLIDER_PAGE_DOWN )
{
- return PerformAction(wxACTION_SLIDER_PAGE_CHANGE, 1);
+ scrollEvent = wxEVT_SCROLL_PAGEDOWN;
+ value = NormalizeValue(m_value + -GetPageSize());
}
- else if ( action == wxACTION_SLIDER_THUMB_DRAG )
+ else if ( action == wxACTION_SLIDER_THUMB_DRAG ||
+ action == wxACTION_SLIDER_THUMB_MOVE )
{
- // no special processing for it
- return TRUE;
+ scrollEvent = wxEVT_SCROLL_THUMBTRACK;
+
+ // we shouldn't generate a command event about this change but we still
+ // should update our value and the slider appearance
+ valueChanged = false;
+ m_value =
+ value = (int)numArg;
+ Refresh();
}
- else if ( action == wxACTION_SLIDER_THUMB_MOVE ||
- action == wxACTION_SLIDER_THUMB_RELEASE )
+ else if ( action == wxACTION_SLIDER_THUMB_RELEASE )
{
- ChangeValueTo((int)numArg);
+ scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
+ value = (int)numArg;
}
else
{
return wxControl::PerformAction(action, numArg, strArg);
}
- return TRUE;
+ // update wxSlider current value and generate wxCommandEvent, except while
+ // dragging the thumb
+ if ( valueChanged )
+ ChangeValueTo(value);
+
+ // also generate more precise wxScrollEvent if applicable
+ if ( scrollEvent != wxEVT_NULL )
+ {
+ wxScrollEvent event(scrollEvent, GetId());
+ event.SetPosition(value);
+ event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent(event);
+ }
+
+ return true;
}
// ----------------------------------------------------------------------------
wxScrollThumb::Shaft wxSlider::HitTest(const wxPoint& pt) const
{
wxRect rectShaft = GetShaftRect();
- if ( !rectShaft.Inside(pt) )
+ wxRect rectThumb;
+ CalcThumbRect(&rectShaft, &rectThumb, NULL);
+
+ // check for possible shaft or thumb hit
+ if (!rectShaft.Inside(pt) && !rectThumb.Inside(pt))
{
return wxScrollThumb::Shaft_None;
}
- // inside the shaft, where is it relatively to the thumb?
- wxRect rectThumb;
- CalcThumbRect(&rectShaft, &rectThumb, NULL);
-
// the position to test and the start and end of the thumb
- wxCoord x, x1, x2;
- if ( IsVert() )
+ wxCoord x, x1, x2, x3, x4;
+ if (IsVert())
{
x = pt.y;
- x1 = rectThumb.GetTop();
- x2 = rectThumb.GetBottom();
+ x1 = rectThumb.GetBottom();
+ x2 = rectShaft.GetBottom();
+ x3 = rectShaft.GetTop();
+ x4 = rectThumb.GetTop();
}
- else // horz
- {
+ else
+ { // horz
x = pt.x;
- x1 = rectThumb.GetLeft();
- x2 = rectThumb.GetRight();
+ x1 = rectShaft.GetLeft();
+ x2 = rectThumb.GetLeft();
+ x3 = rectThumb.GetRight();
+ x4 = rectShaft.GetRight();
}
-
- if ( x < x1 )
+ if ((x1 <= x) && (x < x2))
{
// or to the left
return wxScrollThumb::Shaft_Above;
}
- if ( x > x2 )
- {
+ if ((x3 < x) && (x <= x4)) {
// or to the right
return wxScrollThumb::Shaft_Below;
}
else
m_thumbFlags &= ~flag;
- RefreshThumb();
+ Refresh();
}
}
void wxSlider::OnThumbDragStart(int pos)
{
- PerformAction(wxACTION_SLIDER_THUMB_DRAG, pos);
+ if (IsVert())
+ {
+ PerformAction(wxACTION_SLIDER_THUMB_DRAG, m_max - pos);
+ }
+ else
+ {
+ PerformAction(wxACTION_SLIDER_THUMB_DRAG, pos);
+ }
}
void wxSlider::OnThumbDrag(int pos)
{
- PerformAction(wxACTION_SLIDER_THUMB_MOVE, pos);
+ if (IsVert())
+ {
+ PerformAction(wxACTION_SLIDER_THUMB_MOVE, m_max - pos);
+ }
+ else
+ {
+ PerformAction(wxACTION_SLIDER_THUMB_MOVE, pos);
+ }
}
void wxSlider::OnThumbDragEnd(int pos)
{
- PerformAction(wxACTION_SLIDER_THUMB_RELEASE, pos);
+ if (IsVert())
+ {
+ PerformAction(wxACTION_SLIDER_THUMB_RELEASE, m_max - pos);
+ }
+ else
+ {
+ PerformAction(wxACTION_SLIDER_THUMB_RELEASE, pos);
+ }
}
void wxSlider::OnPageScrollStart()
switch ( keycode )
{
case WXK_HOME:
- action = wxACTION_SLIDER_START;
+ action = wxACTION_SLIDER_END;
break;
case WXK_END:
- action = wxACTION_SLIDER_END;
+ action = wxACTION_SLIDER_START;
break;
- case WXK_LEFT:
+ case WXK_RIGHT:
case WXK_UP:
action = wxACTION_SLIDER_LINE_UP;
break;
- case WXK_RIGHT:
+ case WXK_LEFT:
case WXK_DOWN:
action = wxACTION_SLIDER_LINE_DOWN;
break;
- case WXK_PRIOR:
case WXK_PAGEUP:
action = wxACTION_SLIDER_PAGE_UP;
break;
- case WXK_NEXT:
case WXK_PAGEDOWN:
action = wxACTION_SLIDER_PAGE_DOWN;
break;
}
- if ( !!action )
+ if ( !action.IsEmpty() )
{
consumer->PerformAction(action);
- return TRUE;
+ return true;
}
}
if ( slider->GetThumb().HandleMouse(event) )
{
// processed by the thumb
- return FALSE;
+ return false;
}
return wxStdInputHandler::HandleMouse(consumer, event);
if ( slider->GetThumb().HandleMouseMove(event) )
{
// processed by the thumb
- return FALSE;
+ return false;
}
return wxStdInputHandler::HandleMouseMove(consumer, event);
}
-bool wxStdSliderButtonInputHandler::HandleFocus(wxInputConsumer *consumer,
- const wxFocusEvent& event)
+bool
+wxStdSliderButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
+ const wxFocusEvent& WXUNUSED(event))
{
// slider's appearance changes when it gets/loses focus
- return TRUE;
+ return true;
}
#endif // wxUSE_SLIDER