/////////////////////////////////////////////////////////////////////////////
-// Name: univ/scrolbar.cpp
+// Name: src/univ/scrolbar.cpp
// Purpose: wxScrollBar implementation
// Author: Vadim Zeitlin
// Modified by:
// headers
// ----------------------------------------------------------------------------
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
- #pragma implementation "univscrolbar.h"
-#endif
-
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#if wxUSE_SCROLLBAR
+#include "wx/scrolbar.h"
+
#ifndef WX_PRECOMP
#include "wx/timer.h"
-
#include "wx/dcclient.h"
- #include "wx/scrolbar.h"
#include "wx/validate.h"
+ #include "wx/log.h"
#endif
#include "wx/univ/scrtimer.h"
#include "wx/univ/renderer.h"
#include "wx/univ/inphand.h"
#include "wx/univ/theme.h"
-#include "wx/log.h"
#define WXDEBUG_SCROLLBAR
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);
int range, int pageSize,
bool refresh)
{
- // we only refresh everythign when the range changes, thumb position
+ // we only refresh everything when the range changes, thumb position
// changes are handled in OnIdle
bool needsRefresh = (range != m_range) ||
(thumbSize != m_thumbSize) ||
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( _T("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
}
// NB: we assume that scrollbar events are sequentially numbered
// but this should be ok as other code relies on this as well
scrollType += wxEVT_SCROLL_TOP - wxEVT_SCROLLWIN_TOP;
+ wxScrollEvent event(scrollType, this->GetId(), m_thumbPos,
+ IsVertical() ? wxVERTICAL : wxHORIZONTAL);
+ event.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(event);
+ }
+ else // part of the window
+ {
+ wxScrollWinEvent event(scrollType, m_thumbPos,
+ IsVertical() ? wxVERTICAL : wxHORIZONTAL);
+ event.SetEventObject(this);
+ GetParent()->GetEventHandler()->ProcessEvent(event);
}
-
- wxScrollWinEvent event(scrollType, m_thumbPos,
- IsVertical() ? wxVERTICAL : wxHORIZONTAL);
- event.SetEventObject(this);
- GetParent()->GetEventHandler()->ProcessEvent(event);
}
return true;
return true;
}
+/* static */
+wxInputHandler *wxScrollBar::GetStdInputHandler(wxInputHandler *handlerDef)
+{
+ static wxStdScrollBarInputHandler
+ s_handler(wxTheme::Get()->GetRenderer(), handlerDef);
+
+ return &s_handler;
+}
+
// ============================================================================
// scroll bar input handler
// ============================================================================
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);
}
case WXK_LEFT: action = wxACTION_SCROLL_LINE_UP; break;
case WXK_HOME: action = wxACTION_SCROLL_START; break;
case WXK_END: action = wxACTION_SCROLL_END; break;
- case WXK_PAGEUP:
- case WXK_PRIOR: action = wxACTION_SCROLL_PAGE_UP; break;
- case WXK_PAGEDOWN:
- case WXK_NEXT: action = wxACTION_SCROLL_PAGE_DOWN; break;
+ case WXK_PAGEUP: action = wxACTION_SCROLL_PAGE_UP; break;
+ case WXK_PAGEDOWN: action = wxACTION_SCROLL_PAGE_DOWN; break;
}
if ( !action.IsEmpty() )
{
// 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
if ( m_winCapture )
{
- if ( (m_htLast == wxHT_SCROLLBAR_THUMB) && event.Moving() )
+ if ( (m_htLast == wxHT_SCROLLBAR_THUMB) && event.Dragging() )
{
// make the thumb follow the mouse by keeping the same offset
// between the mouse position and the top/left of the thumb
bool isArrow = scrollbar->GetArrows().HandleMouseMove(event);
- if ( event.Moving() )
+ if ( event.Dragging() )
{
- wxHitTest ht = m_renderer->HitTestScrollbar
- (
- scrollbar,
- event.GetPosition()
- );
+ wxHitTest ht = scrollbar->HitTestBar(event.GetPosition());
if ( ht == m_htLast )
{
// nothing changed
#endif // wxUSE_SCROLLBAR
+#if wxUSE_TIMER
+
// ----------------------------------------------------------------------------
// wxScrollTimer
// ----------------------------------------------------------------------------
}
}
+#endif // wxUSE_TIMER