/////////////////////////////////////////////////////////////////////////////
-// Name: msw/slider95.cpp
-// Purpose: wxSlider95, using the Win95 trackbar control
+// Name: src/msw/slider.cpp
+// Purpose: wxSlider, using the Win95 (and later) trackbar control
// Author: Julian Smart
// Modified by:
// Created: 04/01/98
// declarations
// ============================================================================
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-#pragma implementation "slider95.h"
-#endif
-
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "wx/slider.h"
#include "wx/msw/subwin.h"
-#if !(defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__))
- #include <commctrl.h>
-#endif
+// include <commctrl.h> "properly"
+#include "wx/msw/wrapcctl.h"
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
-// indices of labels in wxSlider95::m_labels
+// indices of labels in wxSlider::m_labels
enum
{
SliderLabel_Min,
wxFLAGS_MEMBER(wxSL_BOTTOM)
wxFLAGS_MEMBER(wxSL_BOTH)
wxFLAGS_MEMBER(wxSL_SELRANGE)
+ wxFLAGS_MEMBER(wxSL_INVERSE)
wxEND_FLAGS( wxSliderStyle )
-IMPLEMENT_DYNAMIC_CLASS_XTI(wxSlider95, wxControl,"wx/scrolbar.h")
+IMPLEMENT_DYNAMIC_CLASS_XTI(wxSlider, wxControl,"wx/slider.h")
-wxBEGIN_PROPERTIES_TABLE(wxSlider95)
- wxEVENT_RANGE_PROPERTY( Scroll , wxEVT_SCROLL_TOP , wxEVT_SCROLL_ENDSCROLL , wxScrollEvent )
+wxBEGIN_PROPERTIES_TABLE(wxSlider)
+ wxEVENT_RANGE_PROPERTY( Scroll , wxEVT_SCROLL_TOP , wxEVT_SCROLL_CHANGED , wxScrollEvent )
wxEVENT_PROPERTY( Updated , wxEVT_COMMAND_SLIDER_UPDATED , wxCommandEvent )
wxPROPERTY( Value , int , SetValue, GetValue , 0, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
wxPROPERTY_FLAGS( WindowStyle , wxSliderStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
wxEND_PROPERTIES_TABLE()
-wxBEGIN_HANDLERS_TABLE(wxSlider95)
+wxBEGIN_HANDLERS_TABLE(wxSlider)
wxEND_HANDLERS_TABLE()
-wxCONSTRUCTOR_8( wxSlider95 , wxWindow* , Parent , wxWindowID , Id , int , Value , int , Minimum , int , Maximum , wxPoint , Position , wxSize , Size , long , WindowStyle )
+wxCONSTRUCTOR_8( wxSlider , wxWindow* , Parent , wxWindowID , Id , int , Value , int , Minimum , int , Maximum , wxPoint , Position , wxSize , Size , long , WindowStyle )
#else
-IMPLEMENT_DYNAMIC_CLASS(wxSlider95, wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl)
#endif
// ============================================================================
-// wxSlider95 implementation
+// wxSlider implementation
// ============================================================================
// ----------------------------------------------------------------------------
// construction
// ----------------------------------------------------------------------------
-void wxSlider95::Init()
+void wxSlider::Init()
{
m_labels = NULL;
m_rangeMax = 0;
m_rangeMin = 0;
m_tickFreq = 0;
+
+ m_isDragging = false;
}
bool
-wxSlider95::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)
-{
+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)
+{
+ // our styles are redundant: wxSL_LEFT/RIGHT imply wxSL_VERTICAL and
+ // wxSL_TOP/BOTTOM imply wxSL_HORIZONTAL, but for backwards compatibility
+ // reasons we can't really change it, instead try to infer the orientation
+ // from the flags given to us here
+ switch ( style & (wxSL_LEFT | wxSL_RIGHT | wxSL_TOP | wxSL_BOTTOM) )
+ {
+ case wxSL_LEFT:
+ case wxSL_RIGHT:
+ style |= wxSL_VERTICAL;
+ break;
+
+ case wxSL_TOP:
+ case wxSL_BOTTOM:
+ style |= wxSL_HORIZONTAL;
+ break;
+
+ case 0:
+ // no specific direction, do we have at least the orientation?
+ if ( !(style & (wxSL_HORIZONTAL | wxSL_VERTICAL)) )
+ {
+ // no, choose default
+ style |= wxSL_BOTTOM | wxSL_HORIZONTAL;
+ }
+ };
+
+ wxASSERT_MSG( !(style & wxSL_VERTICAL) || !(style & wxSL_HORIZONTAL),
+ _T("incompatible slider direction and orientation") );
+
+
// initialize everything
if ( !CreateControl(parent, id, pos, size, style, validator, name) )
return false;
SetValue(value);
SetPageSize((maxValue - minValue)/10);
+ // we need to position the labels correctly if we have them and if
+ // SetSize() hadn't been called before (when best size was determined by
+ // MSWCreateControl()) as in this case they haven't been put in place yet
+ if ( m_labels && size.x != wxDefaultCoord && size.y != wxDefaultCoord )
+ {
+ SetSize(size);
+ }
+
return true;
}
-WXDWORD wxSlider95::MSWGetStyle(long style, WXDWORD *exstyle) const
+WXDWORD wxSlider::MSWGetStyle(long style, WXDWORD *exstyle) const
{
WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle);
- // TBS_HORZ is 0 anyhow, but do mention it explicitly for clarity
+ // TBS_HORZ, TBS_RIGHT and TBS_BOTTOM are 0 but do include them for clarity
msStyle |= style & wxSL_VERTICAL ? TBS_VERT : TBS_HORZ;
- if ( style & wxSL_AUTOTICKS )
- msStyle |= TBS_AUTOTICKS ;
-
- // again, TBS_RIGHT is 0 but do include it for clarity
- if ( style & wxSL_LEFT )
- msStyle |= TBS_LEFT;
- else if ( style & wxSL_RIGHT )
- msStyle |= TBS_RIGHT;
- else if ( style & wxSL_TOP )
- msStyle |= TBS_TOP;
- else if ( style & wxSL_BOTTOM )
- msStyle |= TBS_BOTTOM;
- else if ( style & wxSL_BOTH )
+ if ( style & wxSL_BOTH )
+ {
+ // this fully specifies the style combined with TBS_VERT/HORZ above
msStyle |= TBS_BOTH;
- else if ( !(style & wxSL_AUTOTICKS) )
+ }
+ else // choose one direction
+ {
+ if ( style & wxSL_LEFT )
+ msStyle |= TBS_LEFT;
+ else if ( style & wxSL_RIGHT )
+ msStyle |= TBS_RIGHT;
+ else if ( style & wxSL_TOP )
+ msStyle |= TBS_TOP;
+ else if ( style & wxSL_BOTTOM )
+ msStyle |= TBS_BOTTOM;
+ }
+
+ if ( style & wxSL_AUTOTICKS )
+ msStyle |= TBS_AUTOTICKS;
+ else
msStyle |= TBS_NOTICKS;
if ( style & wxSL_SELRANGE )
return msStyle;
}
-wxSlider95::~wxSlider95()
+wxSlider::~wxSlider()
{
delete m_labels;
}
// event handling
// ----------------------------------------------------------------------------
-bool wxSlider95::MSWOnScroll(int WXUNUSED(orientation),
- WXWORD wParam,
- WXWORD WXUNUSED(pos),
- WXHWND control)
+bool wxSlider::MSWOnScroll(int WXUNUSED(orientation),
+ WXWORD wParam,
+ WXWORD WXUNUSED(pos),
+ WXHWND control)
{
wxEventType scrollEvent;
switch ( wParam )
case SB_THUMBTRACK:
scrollEvent = wxEVT_SCROLL_THUMBTRACK;
+ m_isDragging = true;
break;
case SB_THUMBPOSITION:
- scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
+ if ( m_isDragging )
+ {
+ scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
+ m_isDragging = false;
+ }
+ else
+ {
+ // this seems to only happen when the mouse wheel is used: in
+ // this case, as it might be unexpected to get THUMBRELEASE
+ // without preceding THUMBTRACKs, we don't generate it at all
+ // but generate CHANGED event because the control itself does
+ // not send us SB_ENDSCROLL for whatever reason when mouse
+ // wheel is used
+ scrollEvent = wxEVT_SCROLL_CHANGED;
+ }
break;
case SB_ENDSCROLL:
- scrollEvent = wxEVT_SCROLL_ENDSCROLL;
+ scrollEvent = wxEVT_SCROLL_CHANGED;
break;
default:
return false;
}
- int newPos = (int) ::SendMessage((HWND) control, TBM_GETPOS, 0, 0);
+ int newPos = ValueInvertOrNot((int) ::SendMessage((HWND) control, TBM_GETPOS, 0, 0));
if ( (newPos < GetMin()) || (newPos > GetMax()) )
{
// out of range - but we did process it
return GetEventHandler()->ProcessEvent( cevent );
}
-void wxSlider95::Command (wxCommandEvent & event)
+void wxSlider::Command (wxCommandEvent & event)
{
SetValue (event.GetInt());
ProcessCommand (event);
// geometry stuff
// ----------------------------------------------------------------------------
-wxRect wxSlider95::GetBoundingBox() const
+wxRect wxSlider::GetBoundingBox() const
{
// take care not to call our own functions which would call us recursively
int x, y, w, h;
wxRect rect(x, y, w, h);
if ( m_labels )
- rect.Union(m_labels->GetBoundingBox());
+ {
+ wxRect lrect = m_labels->GetBoundingBox();
+ GetParent()->ScreenToClient(&lrect.x, &lrect.y);
+ rect.Union(lrect);
+ }
return rect;
}
-void wxSlider95::DoGetSize(int *width, int *height) const
+void wxSlider::DoGetSize(int *width, int *height) const
{
wxRect rect = GetBoundingBox();
*height = rect.height;
}
-void wxSlider95::DoGetPosition(int *x, int *y) const
+void wxSlider::DoGetPosition(int *x, int *y) const
{
wxRect rect = GetBoundingBox();
*y = rect.y;
}
-int wxSlider95::GetLabelsSize(int *width) const
+int wxSlider::GetLabelsSize(int *width) const
{
int cy;
return EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
}
-void wxSlider95::DoMoveWindow(int x, int y, int width, int height)
+void wxSlider::DoMoveWindow(int x, int y, int width, int height)
{
// all complications below are because we need to position the labels,
// without them everything is easy
return;
}
+ // be careful to position the slider itself after moving the labels as
+ // otherwise our GetBoundingBox(), which is called from WM_SIZE handler,
+ // would return a wrong result and wrong size would be cached internally
if ( HasFlag(wxSL_VERTICAL) )
{
int wLabel;
int xLabel = HasFlag(wxSL_LEFT) ? x + width - wLabel : x;
- // position the slider itself along the left/right edge
- ::MoveWindow(GetHwnd(),
- HasFlag(wxSL_LEFT) ? x : x + wLabel + HGAP,
- y + hLabel/2,
- width - wLabel - HGAP,
- height - hLabel,
- TRUE);
-
// position all labels: min at the top, value in the middle and max at
// the bottom
- ::MoveWindow((*m_labels)[SliderLabel_Min],
- xLabel, y, wLabel, hLabel, TRUE);
+ DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
+ xLabel, y, wLabel, hLabel);
+
+ DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
+ xLabel, y + (height - hLabel)/2, wLabel, hLabel);
- ::MoveWindow((*m_labels)[SliderLabel_Value],
- xLabel, y + (height - hLabel)/2, wLabel, hLabel, TRUE);
+ DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
+ xLabel, y + height - hLabel, wLabel, hLabel);
- ::MoveWindow((*m_labels)[SliderLabel_Max],
- xLabel, y + height - hLabel, wLabel, hLabel, TRUE);
+ // position the slider itself along the left/right edge
+ wxSliderBase::DoMoveWindow(HasFlag(wxSL_LEFT) ? x : x + wLabel + HGAP,
+ y + hLabel/2,
+ width - wLabel - HGAP,
+ height - hLabel);
}
else // horizontal
{
int yLabel = HasFlag(wxSL_TOP) ? y + height - hLabel : y;
- // position the slider itself along the top/bottom edge
- ::MoveWindow(GetHwnd(),
- x,
- HasFlag(wxSL_TOP) ? y : y + hLabel,
- width,
- height - hLabel,
- TRUE);
-
// position all labels: min on the left, value in the middle and max to
// the right
- ::MoveWindow((*m_labels)[SliderLabel_Min],
- x, yLabel, wLabel, hLabel, TRUE);
+ DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
+ x, yLabel, wLabel, hLabel);
+
+ DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
+ x + (width - wLabel)/2, yLabel, wLabel, hLabel);
- ::MoveWindow((*m_labels)[SliderLabel_Value],
- x + (width - wLabel)/2, yLabel, wLabel, hLabel, TRUE);
+ DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
+ x + width - wLabel, yLabel, wLabel, hLabel);
- ::MoveWindow((*m_labels)[SliderLabel_Max],
- x + width - wLabel, yLabel, wLabel, hLabel, TRUE);
+ // position the slider itself along the top/bottom edge
+ wxSliderBase::DoMoveWindow(x,
+ HasFlag(wxSL_TOP) ? y : y + hLabel,
+ width,
+ height - hLabel);
}
}
-wxSize wxSlider95::DoGetBestSize() const
+wxSize wxSlider::DoGetBestSize() const
{
// these values are arbitrary
static const int length = 100;
- static const int thickness = 26;
+ static const int thumb = 24;
+ static const int ticks = 8;
+ int *width;
wxSize size;
if ( HasFlag(wxSL_VERTICAL) )
{
- size.x = thickness;
+ size.x = thumb;
size.y = length;
+ width = &size.x;
if ( m_labels )
{
else // horizontal
{
size.x = length;
- size.y = thickness;
+ size.y = thumb;
+ width = &size.y;
if ( m_labels )
{
}
}
+ // need extra space to show ticks
+ if ( HasFlag(wxSL_TICKS) )
+ {
+ *width += ticks;
+
+ // and maybe twice as much if we show them on both sides
+ if ( HasFlag(wxSL_BOTH) )
+ *width += ticks;
+ }
+
return size;
}
// slider-specific methods
// ----------------------------------------------------------------------------
-int wxSlider95::GetValue() const
+int wxSlider::GetValue() const
{
- return ::SendMessage(GetHwnd(), TBM_GETPOS, 0, 0);
+ return ValueInvertOrNot(::SendMessage(GetHwnd(), TBM_GETPOS, 0, 0));
}
-void wxSlider95::SetValue(int value)
+void wxSlider::SetValue(int value)
{
- ::SendMessage(GetHwnd(), TBM_SETPOS, (WPARAM)TRUE, (LPARAM)value);
+ ::SendMessage(GetHwnd(), TBM_SETPOS, (WPARAM)TRUE, (LPARAM)ValueInvertOrNot(value));
if ( m_labels )
{
}
}
-void wxSlider95::SetRange(int minValue, int maxValue)
+void wxSlider::SetRange(int minValue, int maxValue)
{
m_rangeMin = minValue;
m_rangeMax = maxValue;
- ::SendMessage(GetHwnd(), TBM_SETRANGE, TRUE, MAKELONG(minValue, maxValue));
+ ::SendMessage(GetHwnd(), TBM_SETRANGEMIN, TRUE, m_rangeMin);
+ ::SendMessage(GetHwnd(), TBM_SETRANGEMAX, TRUE, m_rangeMax);
if ( m_labels )
{
- ::SetWindowText((*m_labels)[SliderLabel_Min], Format(m_rangeMin));
- ::SetWindowText((*m_labels)[SliderLabel_Max], Format(m_rangeMax));
+ ::SetWindowText((*m_labels)[SliderLabel_Min], Format(ValueInvertOrNot(m_rangeMin)));
+ ::SetWindowText((*m_labels)[SliderLabel_Max], Format(ValueInvertOrNot(m_rangeMax)));
}
}
-void wxSlider95::SetTickFreq(int n, int pos)
+void wxSlider::SetTickFreq(int n, int pos)
{
m_tickFreq = n;
::SendMessage( GetHwnd(), TBM_SETTICFREQ, (WPARAM) n, (LPARAM) pos );
}
-void wxSlider95::SetPageSize(int pageSize)
+void wxSlider::SetPageSize(int pageSize)
{
::SendMessage( GetHwnd(), TBM_SETPAGESIZE, (WPARAM) 0, (LPARAM) pageSize );
m_pageSize = pageSize;
}
-int wxSlider95::GetPageSize() const
+int wxSlider::GetPageSize() const
{
return m_pageSize;
}
-void wxSlider95::ClearSel()
+void wxSlider::ClearSel()
{
::SendMessage(GetHwnd(), TBM_CLEARSEL, (WPARAM) TRUE, (LPARAM) 0);
}
-void wxSlider95::ClearTicks()
+void wxSlider::ClearTicks()
{
::SendMessage(GetHwnd(), TBM_CLEARTICS, (WPARAM) TRUE, (LPARAM) 0);
}
-void wxSlider95::SetLineSize(int lineSize)
+void wxSlider::SetLineSize(int lineSize)
{
m_lineSize = lineSize;
::SendMessage(GetHwnd(), TBM_SETLINESIZE, (WPARAM) 0, (LPARAM) lineSize);
}
-int wxSlider95::GetLineSize() const
+int wxSlider::GetLineSize() const
{
return (int)::SendMessage(GetHwnd(), TBM_GETLINESIZE, 0, 0);
}
-int wxSlider95::GetSelEnd() const
+int wxSlider::GetSelEnd() const
{
- return (int)::SendMessage(GetHwnd(), TBM_SETSELEND, 0, 0);
+ return (int)::SendMessage(GetHwnd(), TBM_GETSELEND, 0, 0);
}
-int wxSlider95::GetSelStart() const
+int wxSlider::GetSelStart() const
{
return (int)::SendMessage(GetHwnd(), TBM_GETSELSTART, 0, 0);
}
-void wxSlider95::SetSelection(int minPos, int maxPos)
+void wxSlider::SetSelection(int minPos, int maxPos)
{
::SendMessage(GetHwnd(), TBM_SETSEL,
(WPARAM) TRUE /* redraw */,
(LPARAM) MAKELONG( minPos, maxPos) );
}
-void wxSlider95::SetThumbLength(int len)
+void wxSlider::SetThumbLength(int len)
{
::SendMessage(GetHwnd(), TBM_SETTHUMBLENGTH, (WPARAM) len, (LPARAM) 0);
}
-int wxSlider95::GetThumbLength() const
+int wxSlider::GetThumbLength() const
{
- return (int)::SendMessage( GetHwnd(), TBM_GETTHUMBLENGTH, 0, 0);
+ return (int)::SendMessage( GetHwnd(), TBM_GETTHUMBLENGTH, 0, 0);
}
-void wxSlider95::SetTick(int tickPos)
+void wxSlider::SetTick(int tickPos)
{
- ::SendMessage( GetHwnd(), TBM_SETTIC, (WPARAM) 0, (LPARAM) tickPos );
+ ::SendMessage( GetHwnd(), TBM_SETTIC, (WPARAM) 0, (LPARAM) tickPos );
}
// ----------------------------------------------------------------------------
// composite control methods
// ----------------------------------------------------------------------------
-WXHWND wxSlider95::GetStaticMin() const
+WXHWND wxSlider::GetStaticMin() const
{
return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Min] : NULL;
}
-WXHWND wxSlider95::GetStaticMax() const
+WXHWND wxSlider::GetStaticMax() const
{
return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Max] : NULL;
}
-WXHWND wxSlider95::GetEditValue() const
+WXHWND wxSlider::GetEditValue() const
{
return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Value] : NULL;
}
-bool wxSlider95::ContainsHWND(WXHWND hWnd) const
-{
- return m_labels && m_labels->HasWindow((HWND)hWnd);
-}
-
-bool wxSlider95::Show(bool show)
-{
- if ( !wxSliderBase::Show(show) )
- return false;
-
- if ( m_labels )
- m_labels->Show(show);
-
- return true;
-}
+WX_FORWARD_STD_METHODS_TO_SUBWINDOWS(wxSlider, wxSliderBase, m_labels)
#endif // wxUSE_SLIDER