]> git.saurik.com Git - wxWidgets.git/blame - src/univ/scrolbar.cpp
fixed TLWs resizing to invalidate the DFB surface used for painting
[wxWidgets.git] / src / univ / scrolbar.cpp
CommitLineData
1e6feb95 1/////////////////////////////////////////////////////////////////////////////
fbb526cc 2// Name: src/univ/scrolbar.cpp
1e6feb95
VZ
3// Purpose: wxScrollBar implementation
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 20.08.00
7// RCS-ID: $Id$
442b35b5 8// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
65571936 9// Licence: wxWindows licence
1e6feb95
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
1e6feb95
VZ
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
26#if wxUSE_SCROLLBAR
27
e4db172a
WS
28#include "wx/scrolbar.h"
29
1e6feb95
VZ
30#ifndef WX_PRECOMP
31 #include "wx/timer.h"
1e6feb95 32 #include "wx/dcclient.h"
1e6feb95 33 #include "wx/validate.h"
e4db172a 34 #include "wx/log.h"
1e6feb95
VZ
35#endif
36
37#include "wx/univ/scrtimer.h"
38
39#include "wx/univ/renderer.h"
40#include "wx/univ/inphand.h"
41#include "wx/univ/theme.h"
42
43#define WXDEBUG_SCROLLBAR
44
45#ifndef __WXDEBUG__
46 #undef WXDEBUG_SCROLLBAR
47#endif // !__WXDEBUG__
48
cff7ef89
VS
49#if defined(WXDEBUG_SCROLLBAR) && defined(__WXMSW__) && !defined(__WXMICROWIN__)
50#include "wx/msw/private.h"
51#endif
52
1e6feb95
VZ
53// ----------------------------------------------------------------------------
54// wxScrollBarTimer: this class is used to repeatedly scroll the scrollbar
55// when the mouse is help pressed on the arrow or on the bar. It generates the
56// given scroll action command periodically.
57// ----------------------------------------------------------------------------
58
59class wxScrollBarTimer : public wxScrollTimer
60{
61public:
62 wxScrollBarTimer(wxStdScrollBarInputHandler *handler,
63 const wxControlAction& action,
64 wxScrollBar *control);
65
66protected:
67 virtual bool DoNotify();
68
69private:
70 wxStdScrollBarInputHandler *m_handler;
71 wxControlAction m_action;
72 wxScrollBar *m_control;
73};
74
75// ============================================================================
76// implementation
77// ============================================================================
78
79IMPLEMENT_DYNAMIC_CLASS(wxScrollBar, wxControl)
80
81BEGIN_EVENT_TABLE(wxScrollBar, wxScrollBarBase)
1e6feb95
VZ
82END_EVENT_TABLE()
83
84// ----------------------------------------------------------------------------
85// creation
86// ----------------------------------------------------------------------------
87
88#ifdef __VISUALC__
89 // warning C4355: 'this' : used in base member initializer list
90 #pragma warning(disable:4355) // so what? disable it...
91#endif
92
93wxScrollBar::wxScrollBar()
94 : m_arrows(this)
95{
96 Init();
97}
98
99wxScrollBar::wxScrollBar(wxWindow *parent,
100 wxWindowID id,
101 const wxPoint& pos,
102 const wxSize& size,
103 long style,
104 const wxValidator& validator,
105 const wxString& name)
106 : m_arrows(this)
107{
108 Init();
109
110 (void)Create(parent, id, pos, size, style, validator, name);
111}
112
113#ifdef __VISUALC__
114 // warning C4355: 'this' : used in base member initializer list
115 #pragma warning(default:4355)
116#endif
117
118void wxScrollBar::Init()
119{
120 m_range =
121 m_thumbSize =
122 m_thumbPos =
123 m_pageSize = 0;
124
125 m_thumbPosOld = -1;
126
127 for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
128 {
129 m_elementsState[n] = 0;
130 }
131
a290fa5a 132 m_dirty = false;
1e6feb95
VZ
133}
134
135bool wxScrollBar::Create(wxWindow *parent,
136 wxWindowID id,
137 const wxPoint &pos,
138 const wxSize &size,
139 long style,
140 const wxValidator& validator,
141 const wxString &name)
142{
143 // the scrollbars never have the border
144 style &= ~wxBORDER_MASK;
145
61fef19b 146 if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
a290fa5a 147 return false;
1e6feb95
VZ
148
149 SetBestSize(size);
150
151 // override the cursor of the target window (if any)
152 SetCursor(wxCURSOR_ARROW);
153
154 CreateInputHandler(wxINP_HANDLER_SCROLLBAR);
155
a290fa5a 156 return true;
1e6feb95
VZ
157}
158
159wxScrollBar::~wxScrollBar()
160{
161}
162
c7beb048
VZ
163// ----------------------------------------------------------------------------
164// misc accessors
165// ----------------------------------------------------------------------------
166
167bool wxScrollBar::IsStandalone() const
f809133f 168{
c7beb048
VZ
169 wxWindow *parent = GetParent();
170 if ( !parent )
f809133f 171 {
a290fa5a 172 return true;
f809133f 173 }
c7beb048
VZ
174
175 return (parent->GetScrollbar(wxHORIZONTAL) != this) &&
176 (parent->GetScrollbar(wxVERTICAL) != this);
177}
178
179bool wxScrollBar::AcceptsFocus() const
180{
181 // the window scrollbars never accept focus
182 return wxScrollBarBase::AcceptsFocus() && IsStandalone();
f809133f
RR
183}
184
1e6feb95
VZ
185// ----------------------------------------------------------------------------
186// scrollbar API
187// ----------------------------------------------------------------------------
188
189void wxScrollBar::DoSetThumb(int pos)
190{
191 // don't assert hecks here, we're a private function which is meant to be
192 // called with any args at all
193 if ( pos < 0 )
194 {
195 pos = 0;
196 }
197 else if ( pos > m_range - m_thumbSize )
198 {
199 pos = m_range - m_thumbSize;
200 }
201
202 if ( m_thumbPos == pos )
203 {
204 // nothing changed, avoid refreshes which would provoke flicker
205 return;
206 }
207
208 if ( m_thumbPosOld == -1 )
209 {
210 // remember the old thumb position
211 m_thumbPosOld = m_thumbPos;
212 }
213
214 m_thumbPos = pos;
215
216 // we have to refresh the part of the bar which was under the thumb and the
217 // thumb itself
218 m_elementsState[Element_Thumb] |= wxCONTROL_DIRTY;
219 m_elementsState[m_thumbPos > m_thumbPosOld
220 ? Element_Bar_1 : Element_Bar_2] |= wxCONTROL_DIRTY;
a290fa5a 221 m_dirty = true;
1e6feb95
VZ
222}
223
224int wxScrollBar::GetThumbPosition() const
225{
226 return m_thumbPos;
227}
228
229int wxScrollBar::GetThumbSize() const
230{
231 return m_thumbSize;
232}
233
234int wxScrollBar::GetPageSize() const
235{
236 return m_pageSize;
237}
238
239int wxScrollBar::GetRange() const
240{
241 return m_range;
242}
243
244void wxScrollBar::SetThumbPosition(int pos)
245{
246 wxCHECK_RET( pos >= 0 && pos <= m_range, _T("thumb position out of range") );
247
248 DoSetThumb(pos);
249}
250
251void wxScrollBar::SetScrollbar(int position, int thumbSize,
252 int range, int pageSize,
253 bool refresh)
254{
d6922577 255 // we only refresh everything when the range changes, thumb position
1e6feb95
VZ
256 // changes are handled in OnIdle
257 bool needsRefresh = (range != m_range) ||
258 (thumbSize != m_thumbSize) ||
259 (pageSize != m_pageSize);
260
261 // set all parameters
262 m_range = range;
263 m_thumbSize = thumbSize;
264 SetThumbPosition(position);
265 m_pageSize = pageSize;
266
267 // ignore refresh parameter unless we really need to refresh everything -
268 // there ir a lot of existing code which just calls SetScrollbar() without
269 // specifying the last parameter even though it doesn't need at all to
270 // refresh the window immediately
271 if ( refresh && needsRefresh )
272 {
273 // and update the window
274 Refresh();
275 Update();
276 }
277}
278
279// ----------------------------------------------------------------------------
280// geometry
281// ----------------------------------------------------------------------------
282
283wxSize wxScrollBar::DoGetBestClientSize() const
284{
285 // this dimension is completely arbitrary
286 static const wxCoord SIZE = 140;
287
288 wxSize size = m_renderer->GetScrollbarArrowSize();
289 if ( IsVertical() )
290 {
291 size.y = SIZE;
292 }
293 else // horizontal
294 {
295 size.x = SIZE;
296 }
297
298 return size;
299}
300
301wxScrollArrows::Arrow wxScrollBar::HitTest(const wxPoint& pt) const
302{
303 switch ( m_renderer->HitTestScrollbar(this, pt) )
304 {
305 case wxHT_SCROLLBAR_ARROW_LINE_1:
306 return wxScrollArrows::Arrow_First;
307
308 case wxHT_SCROLLBAR_ARROW_LINE_2:
309 return wxScrollArrows::Arrow_Second;
310
311 default:
312 return wxScrollArrows::Arrow_None;
313 }
314}
315
316// ----------------------------------------------------------------------------
317// drawing
318// ----------------------------------------------------------------------------
319
e39af974 320void wxScrollBar::OnInternalIdle()
21c3670f
VS
321{
322 UpdateThumb();
e28c2d15 323 wxControl::OnInternalIdle();
21c3670f
VS
324}
325
326void wxScrollBar::UpdateThumb()
1e6feb95
VZ
327{
328 if ( m_dirty )
329 {
330 for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
331 {
332 if ( m_elementsState[n] & wxCONTROL_DIRTY )
333 {
334 wxRect rect = GetRenderer()->GetScrollbarRect(this, (Element)n);
335
336 if ( rect.width && rect.height )
337 {
338 // we try to avoid redrawing the entire shaft (which might
339 // be quite long) if possible by only redrawing the area
340 // wich really changed
341 if ( (n == Element_Bar_1 || n == Element_Bar_2) &&
342 (m_thumbPosOld != -1) )
343 {
344 // the less efficient but more reliable (i.e. this will
345 // probably work everywhere) version: refresh the
346 // distance covered by thumb since the last update
347#if 0
348 wxRect rectOld =
349 GetRenderer()->GetScrollbarRect(this,
350 (Element)n,
351 m_thumbPosOld);
352 if ( IsVertical() )
353 {
354 if ( n == Element_Bar_1 )
355 rect.SetTop(rectOld.GetBottom());
356 else
357 rect.SetBottom(rectOld.GetBottom());
358 }
359 else // horizontal
360 {
361 if ( n == Element_Bar_1 )
362 rect.SetLeft(rectOld.GetRight());
363 else
364 rect.SetRight(rectOld.GetRight());
365 }
366#else // efficient version: only repaint the area occupied by
367 // the thumb previously - we can't do better than this
368 rect = GetRenderer()->GetScrollbarRect(this,
369 Element_Thumb,
370 m_thumbPosOld);
371#endif // 0/1
372 }
373
374#ifdef WXDEBUG_SCROLLBAR
a290fa5a 375 static bool s_refreshDebug = false;
1e6feb95
VZ
376 if ( s_refreshDebug )
377 {
378 wxClientDC dc(this);
379 dc.SetBrush(*wxCYAN_BRUSH);
380 dc.SetPen(*wxTRANSPARENT_PEN);
381 dc.DrawRectangle(rect);
382
383 // under Unix we use "--sync" X option for this
8cb172b4 384 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1e6feb95
VZ
385 ::GdiFlush();
386 ::Sleep(200);
387 #endif // __WXMSW__
388 }
389#endif // WXDEBUG_SCROLLBAR
390
a290fa5a 391 Refresh(false, &rect);
1e6feb95
VZ
392 }
393
394 m_elementsState[n] &= ~wxCONTROL_DIRTY;
395 }
396 }
397
a290fa5a 398 m_dirty = false;
1e6feb95 399 }
1e6feb95
VZ
400}
401
402void wxScrollBar::DoDraw(wxControlRenderer *renderer)
403{
404 renderer->DrawScrollbar(this, m_thumbPosOld);
405
406 // clear all dirty flags
a290fa5a 407 m_dirty = false;
1e6feb95
VZ
408 m_thumbPosOld = -1;
409}
410
411// ----------------------------------------------------------------------------
412// state flags
413// ----------------------------------------------------------------------------
414
415static inline wxScrollBar::Element ElementForArrow(wxScrollArrows::Arrow arrow)
416{
417 return arrow == wxScrollArrows::Arrow_First
418 ? wxScrollBar::Element_Arrow_Line_1
419 : wxScrollBar::Element_Arrow_Line_2;
420}
421
422int wxScrollBar::GetArrowState(wxScrollArrows::Arrow arrow) const
423{
424 return GetState(ElementForArrow(arrow));
425}
426
427void wxScrollBar::SetArrowFlag(wxScrollArrows::Arrow arrow, int flag, bool set)
428{
429 Element which = ElementForArrow(arrow);
430 int state = GetState(which);
431 if ( set )
432 state |= flag;
433 else
434 state &= ~flag;
435
436 SetState(which, state);
437}
438
439int wxScrollBar::GetState(Element which) const
440{
441 // if the entire scrollbar is disabled, all of its elements are too
442 int flags = m_elementsState[which];
443 if ( !IsEnabled() )
444 flags |= wxCONTROL_DISABLED;
445
446 return flags;
447}
448
449void wxScrollBar::SetState(Element which, int flags)
450{
451 if ( (int)(m_elementsState[which] & ~wxCONTROL_DIRTY) != flags )
452 {
453 m_elementsState[which] = flags | wxCONTROL_DIRTY;
454
a290fa5a 455 m_dirty = true;
1e6feb95
VZ
456 }
457}
458
459// ----------------------------------------------------------------------------
460// input processing
461// ----------------------------------------------------------------------------
462
463bool wxScrollBar::OnArrow(wxScrollArrows::Arrow arrow)
464{
465 int oldThumbPos = GetThumbPosition();
466 PerformAction(arrow == wxScrollArrows::Arrow_First
467 ? wxACTION_SCROLL_LINE_UP
468 : wxACTION_SCROLL_LINE_DOWN);
469
470 // did we scroll till the end?
471 return GetThumbPosition() != oldThumbPos;
472}
473
474bool wxScrollBar::PerformAction(const wxControlAction& action,
475 long numArg,
476 const wxString& strArg)
477{
478 int thumbOld = m_thumbPos;
479
a290fa5a 480 bool notify = false; // send an event about the change?
1e6feb95
VZ
481
482 wxEventType scrollType;
483
484 // test for thumb move first as these events happen in quick succession
485 if ( action == wxACTION_SCROLL_THUMB_MOVE )
486 {
487 DoSetThumb(numArg);
488
21c3670f
VS
489 // VS: we have to force redraw here, otherwise the thumb will lack
490 // behind mouse cursor
491 UpdateThumb();
492
1e6feb95
VZ
493 scrollType = wxEVT_SCROLLWIN_THUMBTRACK;
494 }
495 else if ( action == wxACTION_SCROLL_LINE_UP )
496 {
497 scrollType = wxEVT_SCROLLWIN_LINEUP;
498 ScrollLines(-1);
499 }
500 else if ( action == wxACTION_SCROLL_LINE_DOWN )
501 {
502 scrollType = wxEVT_SCROLLWIN_LINEDOWN;
503 ScrollLines(1);
504 }
505 else if ( action == wxACTION_SCROLL_PAGE_UP )
506 {
507 scrollType = wxEVT_SCROLLWIN_PAGEUP;
508 ScrollPages(-1);
509 }
510 else if ( action == wxACTION_SCROLL_PAGE_DOWN )
511 {
512 scrollType = wxEVT_SCROLLWIN_PAGEDOWN;
513 ScrollPages(1);
514 }
515 else if ( action == wxACTION_SCROLL_START )
516 {
517 scrollType = wxEVT_SCROLLWIN_THUMBRELEASE; // anything better?
518 ScrollToStart();
519 }
520 else if ( action == wxACTION_SCROLL_END )
521 {
522 scrollType = wxEVT_SCROLLWIN_THUMBRELEASE; // anything better?
523 ScrollToEnd();
524 }
525 else if ( action == wxACTION_SCROLL_THUMB_DRAG )
526 {
527 // we won't use it but this line suppresses the compiler
528 // warning about "variable may be used without having been
529 // initialized"
530 scrollType = wxEVT_NULL;
531 }
532 else if ( action == wxACTION_SCROLL_THUMB_RELEASE )
533 {
534 // always notify about this
a290fa5a 535 notify = true;
1e6feb95
VZ
536 scrollType = wxEVT_SCROLLWIN_THUMBRELEASE;
537 }
538 else
539 return wxControl::PerformAction(action, numArg, strArg);
540
541 // has scrollbar position changed?
542 bool changed = m_thumbPos != thumbOld;
543 if ( notify || changed )
544 {
c7beb048
VZ
545 if ( IsStandalone() )
546 {
547 // we should generate EVT_SCROLL events for the standalone
548 // scrollbars and not the EVT_SCROLLWIN ones
549 //
550 // NB: we assume that scrollbar events are sequentially numbered
551 // but this should be ok as other code relies on this as well
552 scrollType += wxEVT_SCROLL_TOP - wxEVT_SCROLLWIN_TOP;
93c96bab
VZ
553 wxScrollEvent event(scrollType, this->GetId(), m_thumbPos,
554 IsVertical() ? wxVERTICAL : wxHORIZONTAL);
555 event.SetEventObject(this);
35932e05 556 GetEventHandler()->ProcessEvent(event);
93c96bab
VZ
557 }
558 else // part of the window
559 {
560 wxScrollWinEvent event(scrollType, m_thumbPos,
561 IsVertical() ? wxVERTICAL : wxHORIZONTAL);
562 event.SetEventObject(this);
563 GetParent()->GetEventHandler()->ProcessEvent(event);
c7beb048 564 }
1e6feb95
VZ
565 }
566
a290fa5a 567 return true;
1e6feb95
VZ
568}
569
570void wxScrollBar::ScrollToStart()
571{
572 DoSetThumb(0);
573}
574
575void wxScrollBar::ScrollToEnd()
576{
577 DoSetThumb(m_range - m_thumbSize);
578}
579
2b92b572 580bool wxScrollBar::ScrollLines(int nLines)
1e6feb95
VZ
581{
582 DoSetThumb(m_thumbPos + nLines);
a290fa5a 583 return true;
1e6feb95
VZ
584}
585
2b92b572 586bool wxScrollBar::ScrollPages(int nPages)
1e6feb95
VZ
587{
588 DoSetThumb(m_thumbPos + nPages*m_pageSize);
a290fa5a 589 return true;
1e6feb95
VZ
590}
591
9467bdb7
VZ
592/* static */
593wxInputHandler *wxScrollBar::GetStdInputHandler(wxInputHandler *handlerDef)
594{
595 static wxStdScrollBarInputHandler
596 s_handler(wxTheme::Get()->GetRenderer(), handlerDef);
597
598 return &s_handler;
599}
600
1e6feb95
VZ
601// ============================================================================
602// scroll bar input handler
603// ============================================================================
604
605// ----------------------------------------------------------------------------
606// wxScrollBarTimer
607// ----------------------------------------------------------------------------
608
609wxScrollBarTimer::wxScrollBarTimer(wxStdScrollBarInputHandler *handler,
610 const wxControlAction& action,
611 wxScrollBar *control)
612{
613 m_handler = handler;
614 m_action = action;
615 m_control = control;
616}
617
618bool wxScrollBarTimer::DoNotify()
619{
620 return m_handler->OnScrollTimer(m_control, m_action);
621}
622
623// ----------------------------------------------------------------------------
624// wxStdScrollBarInputHandler
625// ----------------------------------------------------------------------------
626
627wxStdScrollBarInputHandler::wxStdScrollBarInputHandler(wxRenderer *renderer,
628 wxInputHandler *handler)
629 : wxStdInputHandler(handler)
630{
631 m_renderer = renderer;
632 m_winCapture = NULL;
633 m_htLast = wxHT_NOWHERE;
634 m_timerScroll = NULL;
635}
636
637wxStdScrollBarInputHandler::~wxStdScrollBarInputHandler()
638{
639 // normally, it's NULL by now but just in case the user somehow managed to
640 // keep the mouse captured until now...
641 delete m_timerScroll;
642}
643
644void wxStdScrollBarInputHandler::SetElementState(wxScrollBar *control,
645 int flag,
646 bool doIt)
647{
648 if ( m_htLast > wxHT_SCROLLBAR_FIRST && m_htLast < wxHT_SCROLLBAR_LAST )
649 {
650 wxScrollBar::Element
651 elem = (wxScrollBar::Element)(m_htLast - wxHT_SCROLLBAR_FIRST - 1);
652
653 int flags = control->GetState(elem);
654 if ( doIt )
655 flags |= flag;
656 else
657 flags &= ~flag;
658 control->SetState(elem, flags);
659 }
660}
661
662bool wxStdScrollBarInputHandler::OnScrollTimer(wxScrollBar *scrollbar,
663 const wxControlAction& action)
664{
665 int oldThumbPos = scrollbar->GetThumbPosition();
666 scrollbar->PerformAction(action);
667 if ( scrollbar->GetThumbPosition() != oldThumbPos )
a290fa5a 668 return true;
1e6feb95
VZ
669
670 // we scrolled till the end
671 m_timerScroll->Stop();
672
a290fa5a 673 return false;
1e6feb95
VZ
674}
675
676void wxStdScrollBarInputHandler::StopScrolling(wxScrollBar *control)
677{
678 // return everything to the normal state
679 if ( m_winCapture )
680 {
681 m_winCapture->ReleaseMouse();
682 m_winCapture = NULL;
683 }
684
685 m_btnCapture = -1;
686
687 if ( m_timerScroll )
688 {
689 delete m_timerScroll;
690 m_timerScroll = NULL;
691 }
692
693 // unpress the arrow and highlight the current element
a290fa5a 694 Press(control, false);
1e6feb95
VZ
695}
696
697wxCoord
698wxStdScrollBarInputHandler::GetMouseCoord(const wxScrollBar *scrollbar,
699 const wxMouseEvent& event) const
700{
701 wxPoint pt = event.GetPosition();
702 return scrollbar->GetWindowStyle() & wxVERTICAL ? pt.y : pt.x;
703}
704
705void wxStdScrollBarInputHandler::HandleThumbMove(wxScrollBar *scrollbar,
706 const wxMouseEvent& event)
707{
708 int thumbPos = GetMouseCoord(scrollbar, event) - m_ofsMouse;
709 thumbPos = m_renderer->PixelToScrollbar(scrollbar, thumbPos);
710 scrollbar->PerformAction(wxACTION_SCROLL_THUMB_MOVE, thumbPos);
711}
712
23645bfa 713bool wxStdScrollBarInputHandler::HandleKey(wxInputConsumer *consumer,
1e6feb95
VZ
714 const wxKeyEvent& event,
715 bool pressed)
716{
717 // we only react to the key presses here
718 if ( pressed )
719 {
720 wxControlAction action;
721 switch ( event.GetKeyCode() )
722 {
723 case WXK_DOWN:
724 case WXK_RIGHT: action = wxACTION_SCROLL_LINE_DOWN; break;
725 case WXK_UP:
726 case WXK_LEFT: action = wxACTION_SCROLL_LINE_UP; break;
727 case WXK_HOME: action = wxACTION_SCROLL_START; break;
728 case WXK_END: action = wxACTION_SCROLL_END; break;
fbb526cc
WS
729 case WXK_PAGEUP: action = wxACTION_SCROLL_PAGE_UP; break;
730 case WXK_PAGEDOWN: action = wxACTION_SCROLL_PAGE_DOWN; break;
1e6feb95
VZ
731 }
732
a290fa5a 733 if ( !action.IsEmpty() )
1e6feb95 734 {
23645bfa 735 consumer->PerformAction(action);
1e6feb95 736
a290fa5a 737 return true;
1e6feb95
VZ
738 }
739 }
740
23645bfa 741 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1e6feb95
VZ
742}
743
23645bfa 744bool wxStdScrollBarInputHandler::HandleMouse(wxInputConsumer *consumer,
1e6feb95
VZ
745 const wxMouseEvent& event)
746{
747 // is this a click event from an acceptable button?
748 int btn = event.GetButton();
9467bdb7 749 if ( btn == wxMOUSE_BTN_LEFT )
1e6feb95
VZ
750 {
751 // determine which part of the window mouse is in
23645bfa 752 wxScrollBar *scrollbar = wxStaticCast(consumer->GetInputWindow(), wxScrollBar);
1e6feb95
VZ
753 wxHitTest ht = m_renderer->HitTestScrollbar
754 (
755 scrollbar,
756 event.GetPosition()
757 );
758
759 // when the mouse is pressed on any scrollbar element, we capture it
760 // and hold capture until the same mouse button is released
761 if ( event.ButtonDown() || event.ButtonDClick() )
762 {
763 if ( !m_winCapture )
764 {
765 m_btnCapture = btn;
23645bfa 766 m_winCapture = consumer->GetInputWindow();
1e6feb95
VZ
767 m_winCapture->CaptureMouse();
768
769 // generate the command
a290fa5a 770 bool hasAction = true;
1e6feb95
VZ
771 wxControlAction action;
772 switch ( ht )
773 {
774 case wxHT_SCROLLBAR_ARROW_LINE_1:
775 action = wxACTION_SCROLL_LINE_UP;
776 break;
777
778 case wxHT_SCROLLBAR_ARROW_LINE_2:
779 action = wxACTION_SCROLL_LINE_DOWN;
780 break;
781
782 case wxHT_SCROLLBAR_BAR_1:
783 action = wxACTION_SCROLL_PAGE_UP;
784 m_ptStartScrolling = event.GetPosition();
785 break;
786
787 case wxHT_SCROLLBAR_BAR_2:
788 action = wxACTION_SCROLL_PAGE_DOWN;
789 m_ptStartScrolling = event.GetPosition();
790 break;
791
792 case wxHT_SCROLLBAR_THUMB:
23645bfa 793 consumer->PerformAction(wxACTION_SCROLL_THUMB_DRAG);
1e6feb95
VZ
794 m_ofsMouse = GetMouseCoord(scrollbar, event) -
795 m_renderer->ScrollbarToPixel(scrollbar);
796
797 // fall through: there is no immediate action
798
799 default:
a290fa5a 800 hasAction = false;
1e6feb95
VZ
801 }
802
803 // remove highlighting
a290fa5a 804 Highlight(scrollbar, false);
1e6feb95
VZ
805 m_htLast = ht;
806
807 // and press the arrow or highlight thumb now instead
808 if ( m_htLast == wxHT_SCROLLBAR_THUMB )
a290fa5a 809 Highlight(scrollbar, true);
1e6feb95 810 else
a290fa5a 811 Press(scrollbar, true);
1e6feb95
VZ
812
813 // start dragging
814 if ( hasAction )
815 {
816 m_timerScroll = new wxScrollBarTimer(this, action,
817 scrollbar);
818 m_timerScroll->StartAutoScroll();
819 }
820 //else: no (immediate) action
821
822 }
823 //else: mouse already captured, nothing to do
824 }
825 // release mouse if the *same* button went up
826 else if ( btn == m_btnCapture )
827 {
828 if ( m_winCapture )
829 {
830 StopScrolling(scrollbar);
831
832 // if we were dragging the thumb, send the last event
833 if ( m_htLast == wxHT_SCROLLBAR_THUMB )
834 {
835 scrollbar->PerformAction(wxACTION_SCROLL_THUMB_RELEASE);
836 }
837
838 m_htLast = ht;
a290fa5a 839 Highlight(scrollbar, true);
1e6feb95
VZ
840 }
841 else
842 {
843 // this is not supposed to happen as the button can't go up
844 // without going down previously and then we'd have
845 // m_winCapture by now
846 wxFAIL_MSG( _T("logic error in mouse capturing code") );
847 }
848 }
849 }
850
23645bfa 851 return wxStdInputHandler::HandleMouse(consumer, event);
1e6feb95
VZ
852}
853
23645bfa 854bool wxStdScrollBarInputHandler::HandleMouseMove(wxInputConsumer *consumer,
1e6feb95
VZ
855 const wxMouseEvent& event)
856{
23645bfa 857 wxScrollBar *scrollbar = wxStaticCast(consumer->GetInputWindow(), wxScrollBar);
1e6feb95
VZ
858
859 if ( m_winCapture )
860 {
ca1ecff4 861 if ( (m_htLast == wxHT_SCROLLBAR_THUMB) && event.Dragging() )
1e6feb95
VZ
862 {
863 // make the thumb follow the mouse by keeping the same offset
864 // between the mouse position and the top/left of the thumb
865 HandleThumbMove(scrollbar, event);
866
a290fa5a 867 return true;
1e6feb95
VZ
868 }
869
870 // no other changes are possible while the mouse is captured
a290fa5a 871 return false;
1e6feb95
VZ
872 }
873
874 bool isArrow = scrollbar->GetArrows().HandleMouseMove(event);
875
ca1ecff4 876 if ( event.Dragging() )
1e6feb95
VZ
877 {
878 wxHitTest ht = m_renderer->HitTestScrollbar
879 (
880 scrollbar,
881 event.GetPosition()
882 );
883 if ( ht == m_htLast )
884 {
885 // nothing changed
a290fa5a 886 return false;
1e6feb95
VZ
887 }
888
889#ifdef DEBUG_MOUSE
890 wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht);
891#endif // DEBUG_MOUSE
892
a290fa5a 893 Highlight(scrollbar, false);
1e6feb95
VZ
894 m_htLast = ht;
895
896 if ( !isArrow )
a290fa5a 897 Highlight(scrollbar, true);
1e6feb95
VZ
898 //else: already done by wxScrollArrows::HandleMouseMove
899 }
900 else if ( event.Leaving() )
901 {
902 if ( !isArrow )
a290fa5a 903 Highlight(scrollbar, false);
1e6feb95
VZ
904
905 m_htLast = wxHT_NOWHERE;
906 }
907 else // event.Entering()
908 {
909 // we don't process this event
a290fa5a 910 return false;
1e6feb95
VZ
911 }
912
913 // we did something
a290fa5a 914 return true;
1e6feb95
VZ
915}
916
917#endif // wxUSE_SCROLLBAR
918
9a6384ca
WS
919#if wxUSE_TIMER
920
1e6feb95
VZ
921// ----------------------------------------------------------------------------
922// wxScrollTimer
923// ----------------------------------------------------------------------------
924
925wxScrollTimer::wxScrollTimer()
926{
a290fa5a 927 m_skipNext = false;
1e6feb95
VZ
928}
929
930void wxScrollTimer::StartAutoScroll()
931{
932 // start scrolling immediately
933 if ( !DoNotify() )
934 {
935 // ... and end it too
936 return;
937 }
938
939 // there is an initial delay before the scrollbar starts scrolling -
940 // implement it by ignoring the first timer expiration and only start
941 // scrolling from the second one
a290fa5a 942 m_skipNext = true;
1e6feb95
VZ
943 Start(200); // FIXME: hardcoded delay
944}
945
946void wxScrollTimer::Notify()
947{
948 if ( m_skipNext )
949 {
950 // scroll normally now - reduce the delay
951 Stop();
952 Start(50); // FIXME: hardcoded delay
953
a290fa5a 954 m_skipNext = false;
1e6feb95
VZ
955 }
956 else
957 {
958 // if DoNotify() returns false, we're already deleted by the timer
959 // event handler, so don't do anything else here
960 (void)DoNotify();
961 }
962}
9a6384ca
WS
963
964#endif // wxUSE_TIMER