#include "wx/univ/inphand.h"
#include "wx/univ/theme.h"
-#define WXDEBUG_SCROLLBAR
-
-#ifndef __WXDEBUG__
- #undef WXDEBUG_SCROLLBAR
-#endif // !__WXDEBUG__
+#if wxDEBUG_LEVEL >= 2
+ #define WXDEBUG_SCROLLBAR
+#endif
#if defined(WXDEBUG_SCROLLBAR) && defined(__WXMSW__) && !defined(__WXMICROWIN__)
#include "wx/msw/private.h"
// implementation
// ============================================================================
-IMPLEMENT_DYNAMIC_CLASS(wxScrollBar, wxControl)
-
BEGIN_EVENT_TABLE(wxScrollBar, wxScrollBarBase)
END_EVENT_TABLE()
if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
return false;
- SetBestSize(size);
+ SetInitialSize(size);
// override the cursor of the target window (if any)
SetCursor(wxCURSOR_ARROW);
void wxScrollBar::SetThumbPosition(int pos)
{
- wxCHECK_RET( pos >= 0 && pos <= m_range, _T("thumb position out of range") );
+ wxCHECK_RET( pos >= 0 && pos <= m_range, wxT("thumb position out of range") );
DoSetThumb(pos);
}
return size;
}
-wxScrollArrows::Arrow wxScrollBar::HitTest(const wxPoint& pt) const
+wxScrollArrows::Arrow wxScrollBar::HitTestArrow(const wxPoint& pt) const
{
- switch ( m_renderer->HitTestScrollbar(this, pt) )
+ switch ( HitTestBar(pt) )
{
case wxHT_SCROLLBAR_ARROW_LINE_1:
return wxScrollArrows::Arrow_First;
}
}
+wxHitTest wxScrollBar::HitTestBar(const wxPoint& pt) const
+{
+ // we only need to work with either x or y coord depending on the
+ // orientation, choose one (but still check the other one to verify if the
+ // mouse is in the window at all)
+ const wxSize sizeArrowSB = m_renderer->GetScrollbarArrowSize();
+
+ wxCoord coord, sizeArrow, sizeTotal;
+ wxSize size = GetSize();
+ if ( GetWindowStyle() & wxVERTICAL )
+ {
+ if ( pt.x < 0 || pt.x > size.x )
+ return wxHT_NOWHERE;
+
+ coord = pt.y;
+ sizeArrow = sizeArrowSB.y;
+ sizeTotal = size.y;
+ }
+ else // horizontal
+ {
+ if ( pt.y < 0 || pt.y > size.y )
+ return wxHT_NOWHERE;
+
+ coord = pt.x;
+ sizeArrow = sizeArrowSB.x;
+ sizeTotal = size.x;
+ }
+
+ // test for the arrows first as it's faster
+ if ( coord < 0 || coord > sizeTotal )
+ {
+ return wxHT_NOWHERE;
+ }
+ else if ( coord < sizeArrow )
+ {
+ return wxHT_SCROLLBAR_ARROW_LINE_1;
+ }
+ else if ( coord > sizeTotal - sizeArrow )
+ {
+ return wxHT_SCROLLBAR_ARROW_LINE_2;
+ }
+ else
+ {
+ // calculate the thumb position in pixels
+ sizeTotal -= 2*sizeArrow;
+ wxCoord thumbStart, thumbEnd;
+ int range = GetRange();
+ if ( !range )
+ {
+ // clicking the scrollbar without range has no effect
+ return wxHT_NOWHERE;
+ }
+ else
+ {
+ GetScrollBarThumbSize(sizeTotal,
+ GetThumbPosition(),
+ GetThumbSize(),
+ range,
+ &thumbStart,
+ &thumbEnd);
+ }
+
+ // now compare with the thumb position
+ coord -= sizeArrow;
+ if ( coord < thumbStart )
+ return wxHT_SCROLLBAR_BAR_1;
+ else if ( coord > thumbEnd )
+ return wxHT_SCROLLBAR_BAR_2;
+ else
+ return wxHT_SCROLLBAR_THUMB;
+ }
+}
+
+/* static */
+void wxScrollBar::GetScrollBarThumbSize(wxCoord length,
+ int thumbPos,
+ int thumbSize,
+ int range,
+ wxCoord *thumbStart,
+ wxCoord *thumbEnd)
+{
+ // the thumb can't be made less than this number of pixels
+ static const wxCoord thumbMinWidth = 8; // FIXME: should be configurable
+
+ *thumbStart = (length*thumbPos) / range;
+ *thumbEnd = (length*(thumbPos + thumbSize)) / range;
+
+ if ( *thumbEnd - *thumbStart < thumbMinWidth )
+ {
+ // adjust the end if possible
+ if ( *thumbStart <= length - thumbMinWidth )
+ {
+ // yes, just make it wider
+ *thumbEnd = *thumbStart + thumbMinWidth;
+ }
+ else // it is at the bottom of the scrollbar
+ {
+ // so move it a bit up
+ *thumbStart = length - thumbMinWidth;
+ *thumbEnd = length;
+ }
+ }
+}
+
+wxRect wxScrollBar::GetScrollbarRect(wxScrollBar::Element elem,
+ int thumbPos) const
+{
+ if ( thumbPos == -1 )
+ {
+ thumbPos = GetThumbPosition();
+ }
+
+ const wxSize sizeArrow = m_renderer->GetScrollbarArrowSize();
+
+ wxSize sizeTotal = GetClientSize();
+ wxCoord *start, *width;
+ wxCoord length, arrow;
+ wxRect rect;
+ if ( IsVertical() )
+ {
+ rect.x = 0;
+ rect.width = sizeTotal.x;
+ length = sizeTotal.y;
+ start = &rect.y;
+ width = &rect.height;
+ arrow = sizeArrow.y;
+ }
+ else // horizontal
+ {
+ rect.y = 0;
+ rect.height = sizeTotal.y;
+ length = sizeTotal.x;
+ start = &rect.x;
+ width = &rect.width;
+ arrow = sizeArrow.x;
+ }
+
+ switch ( elem )
+ {
+ case wxScrollBar::Element_Arrow_Line_1:
+ *start = 0;
+ *width = arrow;
+ break;
+
+ case wxScrollBar::Element_Arrow_Line_2:
+ *start = length - arrow;
+ *width = arrow;
+ break;
+
+ case wxScrollBar::Element_Arrow_Page_1:
+ case wxScrollBar::Element_Arrow_Page_2:
+ // we don't have them at all
+ break;
+
+ case wxScrollBar::Element_Thumb:
+ case wxScrollBar::Element_Bar_1:
+ case wxScrollBar::Element_Bar_2:
+ // we need to calculate the thumb position - do it
+ {
+ length -= 2*arrow;
+ wxCoord thumbStart, thumbEnd;
+ int range = GetRange();
+ if ( !range )
+ {
+ thumbStart =
+ thumbEnd = 0;
+ }
+ else
+ {
+ GetScrollBarThumbSize(length,
+ thumbPos,
+ GetThumbSize(),
+ range,
+ &thumbStart,
+ &thumbEnd);
+ }
+
+ if ( elem == wxScrollBar::Element_Thumb )
+ {
+ *start = thumbStart;
+ *width = thumbEnd - thumbStart;
+ }
+ else if ( elem == wxScrollBar::Element_Bar_1 )
+ {
+ *start = 0;
+ *width = thumbStart;
+ }
+ else // elem == wxScrollBar::Element_Bar_2
+ {
+ *start = thumbEnd;
+ *width = length - thumbEnd;
+ }
+
+ // everything is relative to the start of the shaft so far
+ *start += arrow;
+ }
+ break;
+
+ case wxScrollBar::Element_Max:
+ default:
+ wxFAIL_MSG( wxT("unknown scrollbar element") );
+ }
+
+ return rect;
+}
+
+wxCoord wxScrollBar::GetScrollbarSize() const
+{
+ const wxSize sizeArrowSB = m_renderer->GetScrollbarArrowSize();
+
+ wxCoord sizeArrow, sizeTotal;
+ if ( GetWindowStyle() & wxVERTICAL )
+ {
+ sizeArrow = sizeArrowSB.y;
+ sizeTotal = GetSize().y;
+ }
+ else // horizontal
+ {
+ sizeArrow = sizeArrowSB.x;
+ sizeTotal = GetSize().x;
+ }
+
+ return sizeTotal - 2*sizeArrow;
+}
+
+
+wxCoord wxScrollBar::ScrollbarToPixel(int thumbPos)
+{
+ int range = GetRange();
+ if ( !range )
+ {
+ // the only valid position anyhow
+ return 0;
+ }
+
+ if ( thumbPos == -1 )
+ {
+ // by default use the current thumb position
+ thumbPos = GetThumbPosition();
+ }
+
+ const wxSize sizeArrow = m_renderer->GetScrollbarArrowSize();
+ return (thumbPos * GetScrollbarSize()) / range
+ + (IsVertical() ? sizeArrow.y : sizeArrow.x);
+}
+
+int wxScrollBar::PixelToScrollbar(wxCoord coord)
+{
+ const wxSize sizeArrow = m_renderer->GetScrollbarArrowSize();
+ return ((coord - (IsVertical() ? sizeArrow.y : sizeArrow.x)) *
+ GetRange() ) / GetScrollbarSize();
+}
+
// ----------------------------------------------------------------------------
// drawing
// ----------------------------------------------------------------------------
{
if ( m_elementsState[n] & wxCONTROL_DIRTY )
{
- wxRect rect = GetRenderer()->GetScrollbarRect(this, (Element)n);
+ wxRect rect = GetScrollbarRect((Element)n);
if ( rect.width && rect.height )
{
}
#else // efficient version: only repaint the area occupied by
// the thumb previously - we can't do better than this
- rect = GetRenderer()->GetScrollbarRect(this,
- Element_Thumb,
- m_thumbPosOld);
+ rect = GetScrollbarRect(Element_Thumb, m_thumbPosOld);
#endif // 0/1
}
return true;
}
+/* static */
+wxInputHandler *wxScrollBar::GetStdInputHandler(wxInputHandler *handlerDef)
+{
+ static wxStdScrollBarInputHandler
+ s_handler(wxTheme::Get()->GetRenderer(), handlerDef);
+
+ return &s_handler;
+}
+
// ============================================================================
// scroll bar input handler
// ============================================================================
m_btnCapture = -1;
- if ( m_timerScroll )
- {
- delete m_timerScroll;
- m_timerScroll = NULL;
- }
+ wxDELETE(m_timerScroll);
// unpress the arrow and highlight the current element
Press(control, false);
const wxMouseEvent& event)
{
int thumbPos = GetMouseCoord(scrollbar, event) - m_ofsMouse;
- thumbPos = m_renderer->PixelToScrollbar(scrollbar, thumbPos);
+ thumbPos = scrollbar->PixelToScrollbar(thumbPos);
scrollbar->PerformAction(wxACTION_SCROLL_THUMB_MOVE, thumbPos);
}
{
// is this a click event from an acceptable button?
int btn = event.GetButton();
- if ( (btn != -1) && IsAllowedButton(btn) )
+ if ( btn == wxMOUSE_BTN_LEFT )
{
// determine which part of the window mouse is in
wxScrollBar *scrollbar = wxStaticCast(consumer->GetInputWindow(), wxScrollBar);
- wxHitTest ht = m_renderer->HitTestScrollbar
- (
- scrollbar,
- event.GetPosition()
- );
+ wxHitTest ht = scrollbar->HitTestBar(event.GetPosition());
// when the mouse is pressed on any scrollbar element, we capture it
// and hold capture until the same mouse button is released
case wxHT_SCROLLBAR_THUMB:
consumer->PerformAction(wxACTION_SCROLL_THUMB_DRAG);
m_ofsMouse = GetMouseCoord(scrollbar, event) -
- m_renderer->ScrollbarToPixel(scrollbar);
+ scrollbar->ScrollbarToPixel();
// fall through: there is no immediate action
// this is not supposed to happen as the button can't go up
// without going down previously and then we'd have
// m_winCapture by now
- wxFAIL_MSG( _T("logic error in mouse capturing code") );
+ wxFAIL_MSG( wxT("logic error in mouse capturing code") );
}
}
}
if ( event.Dragging() )
{
- wxHitTest ht = m_renderer->HitTestScrollbar
- (
- scrollbar,
- event.GetPosition()
- );
+ wxHitTest ht = scrollbar->HitTestBar(event.GetPosition());
if ( ht == m_htLast )
{
// nothing changed