tons of changes:
1. wxListBox class added 2. wxInputHandler rewritten (Map() -> Handle()) 3. wxScrollBar redrawing completely changed git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8228 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -30,6 +30,8 @@
|
||||
#if wxUSE_SCROLLBAR
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/timer.h"
|
||||
|
||||
#include "wx/dcclient.h"
|
||||
#include "wx/scrolbar.h"
|
||||
#include "wx/validate.h"
|
||||
@@ -39,12 +41,37 @@
|
||||
#include "wx/univ/inphand.h"
|
||||
#include "wx/univ/theme.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxScrollBarTimer: this class is used to repeatedly scroll the scrollbar
|
||||
// when the mouse is help pressed on the arrow or on the bar. It generates the
|
||||
// given scroll action command periodically.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxScrollBarTimer : public wxTimer
|
||||
{
|
||||
public:
|
||||
wxScrollBarTimer(wxStdScrollBarInputHandler *handler,
|
||||
const wxControlAction& action,
|
||||
wxScrollBar *control);
|
||||
|
||||
virtual void Notify();
|
||||
|
||||
private:
|
||||
wxStdScrollBarInputHandler *m_handler;
|
||||
wxControlAction m_action;
|
||||
wxScrollBar *m_control;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxScrollBar, wxControl)
|
||||
|
||||
BEGIN_EVENT_TABLE(wxScrollBar, wxScrollBarBase)
|
||||
EVT_IDLE(wxScrollBar::OnIdle)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// creation
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -56,10 +83,14 @@ void wxScrollBar::Init()
|
||||
m_thumbPos =
|
||||
m_pageSize = 0;
|
||||
|
||||
m_thumbPosOld = -1;
|
||||
|
||||
for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
|
||||
{
|
||||
m_elementsState[n] = 0;
|
||||
}
|
||||
|
||||
m_dirty = FALSE;
|
||||
}
|
||||
|
||||
bool wxScrollBar::Create(wxWindow *parent,
|
||||
@@ -102,7 +133,20 @@ void wxScrollBar::DoSetThumb(int pos)
|
||||
pos = m_range - m_thumbSize;
|
||||
}
|
||||
|
||||
if ( m_thumbPosOld == -1 )
|
||||
{
|
||||
// remember the old thumb position
|
||||
m_thumbPosOld = m_thumbPos;
|
||||
}
|
||||
|
||||
m_thumbPos = pos;
|
||||
|
||||
// we have to refresh the part of the bar which was under the thumb and the
|
||||
// thumb itself
|
||||
m_elementsState[Element_Thumb] |= wxCONTROL_DIRTY;
|
||||
m_elementsState[m_thumbPos > m_thumbPosOld
|
||||
? Element_Bar_1 : Element_Bar_2] |= wxCONTROL_DIRTY;
|
||||
m_dirty = TRUE;
|
||||
}
|
||||
|
||||
int wxScrollBar::GetThumbPosition() const
|
||||
@@ -130,8 +174,6 @@ void wxScrollBar::SetThumbPosition(int pos)
|
||||
wxCHECK_RET( pos >= 0 && pos <= m_range, _T("thumb position out of range") );
|
||||
|
||||
DoSetThumb(pos);
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void wxScrollBar::SetScrollbar(int position, int thumbSize,
|
||||
@@ -155,34 +197,67 @@ void wxScrollBar::SetScrollbar(int position, int thumbSize,
|
||||
// size management
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxSize wxScrollBar::DoGetBestSize() const
|
||||
wxSize wxScrollBar::DoGetBestClientSize() const
|
||||
{
|
||||
// completely arbitrary
|
||||
return AdjustSize(wxSize(140, 140));
|
||||
return wxSize(140, 140);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// drawing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxScrollBar::OnIdle(wxIdleEvent& event)
|
||||
{
|
||||
if ( m_dirty )
|
||||
{
|
||||
for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
|
||||
{
|
||||
if ( m_elementsState[n] & wxCONTROL_DIRTY )
|
||||
{
|
||||
wxRect rect = GetRenderer()->GetScrollbarRect(this, (Element)n);
|
||||
|
||||
if ( rect.width && rect.height )
|
||||
{
|
||||
// don't refresh the background when refreshing the shaft
|
||||
Refresh(TRUE, //(n != Element_Bar_1) && (n != Element_Bar_2)
|
||||
&rect);
|
||||
}
|
||||
|
||||
m_elementsState[n] &= ~wxCONTROL_DIRTY;
|
||||
}
|
||||
}
|
||||
|
||||
m_dirty = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void wxScrollBar::DoDraw(wxControlRenderer *renderer)
|
||||
{
|
||||
renderer->DrawScrollbar(this);
|
||||
renderer->DrawScrollbar(this, m_thumbPosOld);
|
||||
|
||||
// clear all dirty flags
|
||||
m_dirty = FALSE;
|
||||
m_thumbPosOld = -1;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// input processing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxCoord wxScrollBar::GetMouseCoord(const wxEvent& eventOrig) const
|
||||
void wxScrollBar::SetState(Element which, int flags)
|
||||
{
|
||||
const wxMouseEvent& event = (const wxMouseEvent&)eventOrig;
|
||||
wxPoint pt = event.GetPosition();
|
||||
return GetWindowStyle() & wxVERTICAL ? pt.y : pt.x;
|
||||
if ( (m_elementsState[which] & ~wxCONTROL_DIRTY) != flags )
|
||||
{
|
||||
m_elementsState[which] = flags | wxCONTROL_DIRTY;
|
||||
|
||||
m_dirty = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
bool wxScrollBar::PerformAction(const wxControlAction& action,
|
||||
const wxEvent& event)
|
||||
long numArg,
|
||||
const wxString& strArg)
|
||||
{
|
||||
int thumbOld = m_thumbPos;
|
||||
|
||||
@@ -193,10 +268,7 @@ bool wxScrollBar::PerformAction(const wxControlAction& action,
|
||||
// test for thumb move first as these events happen in quick succession
|
||||
if ( action == wxACTION_SCROLL_THUMB_MOVE )
|
||||
{
|
||||
// make the thumb follow the mouse by keeping the same offset between
|
||||
// the mouse position and the top/left of the thumb
|
||||
int thumbPos = GetMouseCoord(event) - m_ofsMouse;
|
||||
DoSetThumb(GetRenderer()->PixelToScrollbar(this, thumbPos));
|
||||
DoSetThumb(numArg);
|
||||
|
||||
scrollType = wxEVT_SCROLLWIN_THUMBTRACK;
|
||||
}
|
||||
@@ -232,8 +304,10 @@ bool wxScrollBar::PerformAction(const wxControlAction& action,
|
||||
}
|
||||
else if ( action == wxACTION_SCROLL_THUMB_DRAG )
|
||||
{
|
||||
m_ofsMouse = GetMouseCoord(event) -
|
||||
GetRenderer()->ScrollbarToPixel(this);
|
||||
// we won't use it but this line suppresses the compiler
|
||||
// warning about "variable may be used without having been
|
||||
// initialized"
|
||||
scrollType = wxEVT_NULL;
|
||||
}
|
||||
else if ( action == wxACTION_SCROLL_THUMB_RELEASE )
|
||||
{
|
||||
@@ -242,7 +316,7 @@ bool wxScrollBar::PerformAction(const wxControlAction& action,
|
||||
scrollType = wxEVT_SCROLLWIN_THUMBRELEASE;
|
||||
}
|
||||
else
|
||||
return wxControl::PerformAction(action, event);
|
||||
return wxControl::PerformAction(action, numArg, strArg);
|
||||
|
||||
// has scrollbar position changed?
|
||||
bool changed = m_thumbPos != thumbOld;
|
||||
@@ -254,8 +328,7 @@ bool wxScrollBar::PerformAction(const wxControlAction& action,
|
||||
GetParent()->GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
|
||||
// refresh if something changed
|
||||
return changed;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void wxScrollBar::ScrollToStart()
|
||||
@@ -278,5 +351,333 @@ void wxScrollBar::ScrollPages(int nPages)
|
||||
DoSetThumb(m_thumbPos + nPages*m_pageSize);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// scroll bar input handler
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxScrollBarTimer
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxScrollBarTimer::wxScrollBarTimer(wxStdScrollBarInputHandler *handler,
|
||||
const wxControlAction& action,
|
||||
wxScrollBar *control)
|
||||
{
|
||||
m_handler = handler;
|
||||
m_action = action;
|
||||
m_control = control;
|
||||
}
|
||||
|
||||
void wxScrollBarTimer::Notify()
|
||||
{
|
||||
m_handler->OnScrollTimer(m_control, m_action);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxStdScrollBarInputHandler
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxStdScrollBarInputHandler::wxStdScrollBarInputHandler(wxRenderer *renderer,
|
||||
wxInputHandler *handler)
|
||||
: wxStdInputHandler(handler)
|
||||
{
|
||||
m_renderer = renderer;
|
||||
m_winCapture = NULL;
|
||||
m_htLast = wxHT_NOWHERE;
|
||||
m_timerScroll = NULL;
|
||||
}
|
||||
|
||||
wxStdScrollBarInputHandler::~wxStdScrollBarInputHandler()
|
||||
{
|
||||
// normally, it's NULL by now but just in case the user somehow managed to
|
||||
// keep the mouse captured until now...
|
||||
delete m_timerScroll;
|
||||
}
|
||||
|
||||
void wxStdScrollBarInputHandler::SetElementState(wxScrollBar *control,
|
||||
int flag,
|
||||
bool doIt)
|
||||
{
|
||||
if ( m_htLast > wxHT_SCROLLBAR_FIRST && m_htLast < wxHT_SCROLLBAR_LAST )
|
||||
{
|
||||
wxScrollBar::Element
|
||||
elem = (wxScrollBar::Element)(m_htLast - wxHT_SCROLLBAR_FIRST - 1);
|
||||
|
||||
int flags = control->GetState(elem);
|
||||
if ( doIt )
|
||||
flags |= flag;
|
||||
else
|
||||
flags &= ~flag;
|
||||
control->SetState(elem, flags);
|
||||
}
|
||||
}
|
||||
|
||||
bool wxStdScrollBarInputHandler::OnScrollTimer(wxScrollBar *scrollbar,
|
||||
const wxControlAction& action)
|
||||
{
|
||||
int oldThumbPos = scrollbar->GetThumbPosition();
|
||||
scrollbar->PerformAction(action);
|
||||
if ( scrollbar->GetThumbPosition() != oldThumbPos )
|
||||
return TRUE;
|
||||
|
||||
// we scrolled till the end
|
||||
m_timerScroll->Stop();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void wxStdScrollBarInputHandler::StopScrolling(wxScrollBar *control)
|
||||
{
|
||||
// return everything to the normal state
|
||||
if ( m_winCapture )
|
||||
{
|
||||
m_winCapture->ReleaseMouse();
|
||||
m_winCapture = NULL;
|
||||
}
|
||||
|
||||
m_btnCapture = -1;
|
||||
|
||||
if ( m_timerScroll )
|
||||
{
|
||||
delete m_timerScroll;
|
||||
m_timerScroll = NULL;
|
||||
}
|
||||
|
||||
// unpress the arrow and highlight the current element
|
||||
Press(control, FALSE);
|
||||
}
|
||||
|
||||
wxCoord
|
||||
wxStdScrollBarInputHandler::GetMouseCoord(const wxScrollBar *scrollbar,
|
||||
const wxMouseEvent& event) const
|
||||
{
|
||||
wxPoint pt = event.GetPosition();
|
||||
return scrollbar->GetWindowStyle() & wxVERTICAL ? pt.y : pt.x;
|
||||
}
|
||||
|
||||
void wxStdScrollBarInputHandler::HandleThumbMove(wxScrollBar *scrollbar,
|
||||
const wxMouseEvent& event)
|
||||
{
|
||||
int thumbPos = GetMouseCoord(scrollbar, event) - m_ofsMouse;
|
||||
thumbPos = m_renderer->PixelToScrollbar(scrollbar, thumbPos);
|
||||
scrollbar->PerformAction(wxACTION_SCROLL_THUMB_MOVE, thumbPos);
|
||||
}
|
||||
|
||||
bool wxStdScrollBarInputHandler::HandleKey(wxControl *control,
|
||||
const wxKeyEvent& event,
|
||||
bool pressed)
|
||||
{
|
||||
// we only react to the key presses here
|
||||
if ( pressed )
|
||||
{
|
||||
wxControlAction action;
|
||||
switch ( event.GetKeyCode() )
|
||||
{
|
||||
case WXK_DOWN:
|
||||
case WXK_RIGHT: action = wxACTION_SCROLL_LINE_DOWN; break;
|
||||
case WXK_UP:
|
||||
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_PRIOR: action = wxACTION_SCROLL_PAGE_UP; break;
|
||||
case WXK_NEXT: action = wxACTION_SCROLL_PAGE_DOWN; break;
|
||||
}
|
||||
|
||||
if ( !!action )
|
||||
{
|
||||
control->PerformAction(action);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return wxStdInputHandler::HandleKey(control, event, pressed);
|
||||
}
|
||||
|
||||
bool wxStdScrollBarInputHandler::HandleMouse(wxControl *control,
|
||||
const wxMouseEvent& event)
|
||||
{
|
||||
// is this a click event from an acceptable button?
|
||||
int btn = -1;
|
||||
if ( event.IsButton() )
|
||||
{
|
||||
for ( int i = 1; i <= 3; i++ )
|
||||
{
|
||||
if ( event.Button(i) )
|
||||
{
|
||||
btn = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wxASSERT_MSG( btn != -1, _T("unknown mouse button") );
|
||||
}
|
||||
|
||||
if ( (btn != -1) && IsAllowedButton(btn) )
|
||||
{
|
||||
// determine which part of the window mouse is in
|
||||
wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
|
||||
wxHitTest ht = m_renderer->HitTestScrollbar
|
||||
(
|
||||
scrollbar,
|
||||
event.GetPosition()
|
||||
);
|
||||
|
||||
// when the mouse is pressed on any scrollbar element, we capture it
|
||||
// and hold capture until the same mouse button is released
|
||||
if ( event.ButtonDown() || event.ButtonDClick() )
|
||||
{
|
||||
if ( !m_winCapture )
|
||||
{
|
||||
m_btnCapture = btn;
|
||||
m_winCapture = control;
|
||||
m_winCapture->CaptureMouse();
|
||||
|
||||
// generate the command
|
||||
bool hasAction = TRUE;
|
||||
wxControlAction action;
|
||||
switch ( ht )
|
||||
{
|
||||
case wxHT_SCROLLBAR_ARROW_LINE_1:
|
||||
action = wxACTION_SCROLL_LINE_UP;
|
||||
break;
|
||||
|
||||
case wxHT_SCROLLBAR_ARROW_LINE_2:
|
||||
action = wxACTION_SCROLL_LINE_DOWN;
|
||||
break;
|
||||
|
||||
case wxHT_SCROLLBAR_BAR_1:
|
||||
action = wxACTION_SCROLL_PAGE_UP;
|
||||
m_ptStartScrolling = event.GetPosition();
|
||||
break;
|
||||
|
||||
case wxHT_SCROLLBAR_BAR_2:
|
||||
action = wxACTION_SCROLL_PAGE_DOWN;
|
||||
m_ptStartScrolling = event.GetPosition();
|
||||
break;
|
||||
|
||||
case wxHT_SCROLLBAR_THUMB:
|
||||
control->PerformAction(wxACTION_SCROLL_THUMB_DRAG);
|
||||
m_ofsMouse = GetMouseCoord(scrollbar, event) -
|
||||
m_renderer->ScrollbarToPixel(scrollbar);
|
||||
|
||||
// fall through: there is no immediate action
|
||||
|
||||
default:
|
||||
hasAction = FALSE;
|
||||
}
|
||||
|
||||
// remove highlighting
|
||||
Highlight(scrollbar, FALSE);
|
||||
m_htLast = ht;
|
||||
|
||||
// and press the arrow or highlight thumb now instead
|
||||
if ( m_htLast == wxHT_SCROLLBAR_THUMB )
|
||||
Highlight(scrollbar, TRUE);
|
||||
else
|
||||
Press(scrollbar, TRUE);
|
||||
|
||||
// start dragging
|
||||
if ( hasAction )
|
||||
{
|
||||
m_timerScroll = new wxScrollBarTimer(this,
|
||||
action,
|
||||
scrollbar);
|
||||
// start scrolling immediately
|
||||
m_timerScroll->Notify();
|
||||
|
||||
// and continue it later
|
||||
m_timerScroll->Start(50); // FIXME hardcoded delay
|
||||
}
|
||||
//else: no (immediate) action
|
||||
|
||||
}
|
||||
//else: mouse already captured, nothing to do
|
||||
}
|
||||
// release mouse if the *same* button went up
|
||||
else if ( btn == m_btnCapture )
|
||||
{
|
||||
if ( m_winCapture )
|
||||
{
|
||||
StopScrolling(scrollbar);
|
||||
|
||||
// if we were dragging the thumb, send the last event
|
||||
if ( m_htLast == wxHT_SCROLLBAR_THUMB )
|
||||
{
|
||||
scrollbar->PerformAction(wxACTION_SCROLL_THUMB_RELEASE);
|
||||
}
|
||||
|
||||
m_htLast = ht;
|
||||
Highlight(scrollbar, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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") );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wxStdInputHandler::HandleMouse(control, event);
|
||||
}
|
||||
|
||||
bool wxStdScrollBarInputHandler::HandleMouseMove(wxControl *control,
|
||||
const wxMouseEvent& event)
|
||||
{
|
||||
wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
|
||||
|
||||
if ( m_winCapture )
|
||||
{
|
||||
if ( (m_htLast == wxHT_SCROLLBAR_THUMB) && event.Moving() )
|
||||
{
|
||||
// make the thumb follow the mouse by keeping the same offset
|
||||
// between the mouse position and the top/left of the thumb
|
||||
HandleThumbMove(scrollbar, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// no other changes are possible while the mouse is captured
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( event.Moving() )
|
||||
{
|
||||
wxHitTest ht = m_renderer->HitTestScrollbar
|
||||
(
|
||||
scrollbar,
|
||||
event.GetPosition()
|
||||
);
|
||||
if ( ht == m_htLast )
|
||||
{
|
||||
// nothing changed
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MOUSE
|
||||
wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht);
|
||||
#endif // DEBUG_MOUSE
|
||||
|
||||
Highlight(scrollbar, FALSE);
|
||||
m_htLast = ht;
|
||||
Highlight(scrollbar, TRUE);
|
||||
}
|
||||
else if ( event.Leaving() )
|
||||
{
|
||||
Highlight(scrollbar, FALSE);
|
||||
m_htLast = wxHT_NOWHERE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't process this event
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// we did something
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif // wxUSE_SCROLLBAR
|
||||
|
||||
|
Reference in New Issue
Block a user