]> git.saurik.com Git - wxWidgets.git/blame - src/generic/scrlwing.cpp
fixed setting selection when there are NULL pages in the tree
[wxWidgets.git] / src / generic / scrlwing.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
de6185e2 2// Name: src/generic/scrolwin.cpp
d32e78bd 3// Purpose: wxScrolledWindow implementation
c801d85f 4// Author: Julian Smart
566d84a7
RL
5// Modified by: Vadim Zeitlin on 31.08.00: wxScrollHelper allows to implement.
6// Ron Lee on 10.4.02: virtual size / auto scrollbars et al.
c801d85f
KB
7// Created: 01/02/97
8// RCS-ID: $Id$
77ffb593 9// Copyright: (c) wxWidgets team
65571936 10// Licence: wxWindows licence
c801d85f
KB
11/////////////////////////////////////////////////////////////////////////////
12
d80cd92a
VZ
13// ============================================================================
14// declarations
15// ============================================================================
16
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
bcd055ae
JJ
21#ifdef __VMS
22#define XtDisplay XTDISPLAY
23#endif
24
c801d85f
KB
25// For compilers that support precompilation, includes "wx.h".
26#include "wx/wxprec.h"
27
c801d85f 28#ifdef __BORLANDC__
d80cd92a 29 #pragma hdrstop
c801d85f
KB
30#endif
31
de6185e2
WS
32#include "wx/scrolwin.h"
33
34#ifndef WX_PRECOMP
35 #include "wx/utils.h"
36#endif
37
d80cd92a
VZ
38#include "wx/dcclient.h"
39
053f9cc1 40#include "wx/panel.h"
4b316329 41#if wxUSE_TIMER
1e6feb95 42#include "wx/timer.h"
4b316329 43#endif
95d60b24 44#include "wx/sizer.h"
2a201ef8 45#include "wx/recguard.h"
c801d85f 46
48d1144b 47#ifdef __WXMSW__
1e6feb95 48 #include <windows.h> // for DLGC_WANTARROWS
7acf6a92 49 #include "wx/msw/winundef.h"
48d1144b
JS
50#endif
51
a91b47e8
JS
52#ifdef __WXMOTIF__
53// For wxRETAINED implementation
338dd992
JJ
54#ifdef __VMS__ //VMS's Xm.h is not (yet) compatible with C++
55 //This code switches off the compiler warnings
56# pragma message disable nosimpint
57#endif
a91b47e8 58#include <Xm/Xm.h>
338dd992
JJ
59#ifdef __VMS__
60# pragma message enable nosimpint
61#endif
a91b47e8
JS
62#endif
63
066f1b7a 64/*
ca65c044
WS
65 TODO PROPERTIES
66 style wxHSCROLL | wxVSCROLL
066f1b7a
SC
67*/
68
d80cd92a 69// ----------------------------------------------------------------------------
1e6feb95
VZ
70// wxScrollHelperEvtHandler: intercept the events from the window and forward
71// them to wxScrollHelper
d80cd92a
VZ
72// ----------------------------------------------------------------------------
73
349efbaa 74class WXDLLEXPORT wxScrollHelperEvtHandler : public wxEvtHandler
1e6feb95
VZ
75{
76public:
77 wxScrollHelperEvtHandler(wxScrollHelper *scrollHelper)
78 {
79 m_scrollHelper = scrollHelper;
80 }
d80cd92a 81
1e6feb95
VZ
82 virtual bool ProcessEvent(wxEvent& event);
83
ca65c044 84 void ResetDrawnFlag() { m_hasDrawnWindow = false; }
349efbaa 85
1e6feb95
VZ
86private:
87 wxScrollHelper *m_scrollHelper;
349efbaa
VZ
88
89 bool m_hasDrawnWindow;
22f3361e
VZ
90
91 DECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler)
1e6feb95
VZ
92};
93
4b316329 94#if wxUSE_TIMER
1e6feb95
VZ
95// ----------------------------------------------------------------------------
96// wxAutoScrollTimer: the timer used to generate a stream of scroll events when
97// a captured mouse is held outside the window
98// ----------------------------------------------------------------------------
99
100class wxAutoScrollTimer : public wxTimer
101{
102public:
103 wxAutoScrollTimer(wxWindow *winToScroll, wxScrollHelper *scroll,
104 wxEventType eventTypeToSend,
105 int pos, int orient);
106
107 virtual void Notify();
108
109private:
110 wxWindow *m_win;
111 wxScrollHelper *m_scrollHelper;
112 wxEventType m_eventType;
113 int m_pos,
114 m_orient;
22f3361e
VZ
115
116 DECLARE_NO_COPY_CLASS(wxAutoScrollTimer)
1e6feb95 117};
d80cd92a
VZ
118
119// ============================================================================
120// implementation
121// ============================================================================
122
123// ----------------------------------------------------------------------------
1e6feb95 124// wxAutoScrollTimer
d80cd92a
VZ
125// ----------------------------------------------------------------------------
126
1e6feb95
VZ
127wxAutoScrollTimer::wxAutoScrollTimer(wxWindow *winToScroll,
128 wxScrollHelper *scroll,
129 wxEventType eventTypeToSend,
130 int pos, int orient)
c801d85f 131{
1e6feb95
VZ
132 m_win = winToScroll;
133 m_scrollHelper = scroll;
134 m_eventType = eventTypeToSend;
135 m_pos = pos;
136 m_orient = orient;
c801d85f
KB
137}
138
1e6feb95 139void wxAutoScrollTimer::Notify()
c801d85f 140{
1e6feb95
VZ
141 // only do all this as long as the window is capturing the mouse
142 if ( wxWindow::GetCapture() != m_win )
143 {
144 Stop();
145 }
146 else // we still capture the mouse, continue generating events
147 {
148 // first scroll the window if we are allowed to do it
149 wxScrollWinEvent event1(m_eventType, m_pos, m_orient);
150 event1.SetEventObject(m_win);
151 if ( m_scrollHelper->SendAutoScrollEvents(event1) &&
152 m_win->GetEventHandler()->ProcessEvent(event1) )
153 {
154 // and then send a pseudo mouse-move event to refresh the selection
155 wxMouseEvent event2(wxEVT_MOTION);
156 wxGetMousePosition(&event2.m_x, &event2.m_y);
157
158 // the mouse event coordinates should be client, not screen as
159 // returned by wxGetMousePosition
160 wxWindow *parentTop = m_win;
161 while ( parentTop->GetParent() )
162 parentTop = parentTop->GetParent();
163 wxPoint ptOrig = parentTop->GetPosition();
164 event2.m_x -= ptOrig.x;
165 event2.m_y -= ptOrig.y;
166
167 event2.SetEventObject(m_win);
168
169 // FIXME: we don't fill in the other members - ok?
170
171 m_win->GetEventHandler()->ProcessEvent(event2);
172 }
173 else // can't scroll further, stop
174 {
175 Stop();
176 }
177 }
178}
4b316329 179#endif
1e6feb95
VZ
180
181// ----------------------------------------------------------------------------
182// wxScrollHelperEvtHandler
183// ----------------------------------------------------------------------------
184
185bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
186{
9a268018 187 wxEventType evType = event.GetEventType();
2feed004 188
349efbaa
VZ
189 // the explanation of wxEVT_PAINT processing hack: for historic reasons
190 // there are 2 ways to process this event in classes deriving from
191 // wxScrolledWindow. The user code may
192 //
193 // 1. override wxScrolledWindow::OnDraw(dc)
194 // 2. define its own OnPaint() handler
195 //
196 // In addition, in wxUniversal wxWindow defines OnPaint() itself and
197 // always processes the draw event, so we can't just try the window
198 // OnPaint() first and call our HandleOnPaint() if it doesn't process it
199 // (the latter would never be called in wxUniversal).
200 //
201 // So the solution is to have a flag telling us whether the user code drew
202 // anything in the window. We set it to true here but reset it to false in
203 // wxScrolledWindow::OnPaint() handler (which wouldn't be called if the
204 // user code defined OnPaint() in the derived class)
ca65c044 205 m_hasDrawnWindow = true;
349efbaa 206
ff186591
VZ
207 // pass it on to the real handler
208 bool processed = wxEvtHandler::ProcessEvent(event);
209
210 // always process the size events ourselves, even if the user code handles
211 // them as well, as we need to AdjustScrollbars()
212 //
213 // NB: it is important to do it after processing the event in the normal
214 // way as HandleOnSize() may generate a wxEVT_SIZE itself if the
215 // scrollbar[s] (dis)appear and it should be seen by the user code
216 // after this one
217 if ( evType == wxEVT_SIZE )
218 {
219 m_scrollHelper->HandleOnSize((wxSizeEvent &)event);
220
ca65c044 221 return true;
ff186591
VZ
222 }
223
224 if ( processed )
349efbaa
VZ
225 {
226 // normally, nothing more to do here - except if it was a paint event
227 // which wasn't really processed, then we'll try to call our
228 // OnDraw() below (from HandleOnPaint)
c6b81ceb 229 if ( m_hasDrawnWindow || event.IsCommandEvent() )
349efbaa 230 {
ca65c044 231 return true;
349efbaa
VZ
232 }
233 }
2feed004 234
ca65c044 235 // reset the skipped flag to false as it might have been set to true in
1e6feb95 236 // ProcessEvent() above
ca65c044 237 event.Skip(false);
1e6feb95 238
e421922f
VZ
239 if ( evType == wxEVT_PAINT )
240 {
241 m_scrollHelper->HandleOnPaint((wxPaintEvent &)event);
ca65c044 242 return true;
e421922f 243 }
1e6feb95 244
e421922f
VZ
245 if ( evType == wxEVT_SCROLLWIN_TOP ||
246 evType == wxEVT_SCROLLWIN_BOTTOM ||
247 evType == wxEVT_SCROLLWIN_LINEUP ||
248 evType == wxEVT_SCROLLWIN_LINEDOWN ||
249 evType == wxEVT_SCROLLWIN_PAGEUP ||
250 evType == wxEVT_SCROLLWIN_PAGEDOWN ||
251 evType == wxEVT_SCROLLWIN_THUMBTRACK ||
252 evType == wxEVT_SCROLLWIN_THUMBRELEASE )
253 {
254 m_scrollHelper->HandleOnScroll((wxScrollWinEvent &)event);
1e6feb95 255 return !event.GetSkipped();
e421922f 256 }
1e6feb95 257
e421922f
VZ
258 if ( evType == wxEVT_ENTER_WINDOW )
259 {
260 m_scrollHelper->HandleOnMouseEnter((wxMouseEvent &)event);
261 }
262 else if ( evType == wxEVT_LEAVE_WINDOW )
263 {
264 m_scrollHelper->HandleOnMouseLeave((wxMouseEvent &)event);
265 }
266#if wxUSE_MOUSEWHEEL
267 else if ( evType == wxEVT_MOUSEWHEEL )
268 {
269 m_scrollHelper->HandleOnMouseWheel((wxMouseEvent &)event);
270 }
271#endif // wxUSE_MOUSEWHEEL
e421922f
VZ
272 else if ( evType == wxEVT_CHAR )
273 {
274 m_scrollHelper->HandleOnChar((wxKeyEvent &)event);
275 return !event.GetSkipped();
1e6feb95
VZ
276 }
277
ca65c044 278 return false;
1e6feb95
VZ
279}
280
281// ----------------------------------------------------------------------------
282// wxScrollHelper construction
283// ----------------------------------------------------------------------------
284
285wxScrollHelper::wxScrollHelper(wxWindow *win)
286{
d32e78bd
VZ
287 wxASSERT_MSG( win, _T("associated window can't be NULL in wxScrollHelper") );
288
1e6feb95
VZ
289 m_xScrollPixelsPerLine =
290 m_yScrollPixelsPerLine =
291 m_xScrollPosition =
292 m_yScrollPosition =
293 m_xScrollLines =
294 m_yScrollLines =
295 m_xScrollLinesPerPage =
139adb6a 296 m_yScrollLinesPerPage = 0;
1e6feb95
VZ
297
298 m_xScrollingEnabled =
ca65c044 299 m_yScrollingEnabled = true;
1e6feb95
VZ
300
301 m_scaleX =
139adb6a 302 m_scaleY = 1.0;
24ce4c18 303#if wxUSE_MOUSEWHEEL
d2c52078 304 m_wheelRotation = 0;
24ce4c18 305#endif
a58a12e9 306
1e6feb95
VZ
307 m_win =
308 m_targetWindow = (wxWindow *)NULL;
139adb6a 309
1e6feb95 310 m_timerAutoScroll = (wxTimer *)NULL;
d7da9756 311
349efbaa
VZ
312 m_handler = NULL;
313
d32e78bd
VZ
314 m_win = win;
315
316 // by default, the associated window is also the target window
317 DoSetTargetWindow(win);
1e6feb95 318}
d7da9756 319
1e6feb95 320wxScrollHelper::~wxScrollHelper()
d80cd92a 321{
1e6feb95
VZ
322 StopAutoScrolling();
323
349efbaa 324 DeleteEvtHandler();
d80cd92a
VZ
325}
326
327// ----------------------------------------------------------------------------
328// setting scrolling parameters
329// ----------------------------------------------------------------------------
330
1e6feb95
VZ
331void wxScrollHelper::SetScrollbars(int pixelsPerUnitX,
332 int pixelsPerUnitY,
333 int noUnitsX,
334 int noUnitsY,
335 int xPos,
336 int yPos,
337 bool noRefresh)
c801d85f 338{
b0486e0d
SN
339 int xpos, ypos;
340
341 CalcUnscrolledPosition(xPos, yPos, &xpos, &ypos);
139adb6a
RR
342 bool do_refresh =
343 (
c801d85f 344 (noUnitsX != 0 && m_xScrollLines == 0) ||
566d84a7 345 (noUnitsX < m_xScrollLines && xpos > pixelsPerUnitX * noUnitsX) ||
b0486e0d 346
c801d85f 347 (noUnitsY != 0 && m_yScrollLines == 0) ||
566d84a7 348 (noUnitsY < m_yScrollLines && ypos > pixelsPerUnitY * noUnitsY) ||
c801d85f 349 (xPos != m_xScrollPosition) ||
b0486e0d 350 (yPos != m_yScrollPosition)
139adb6a 351 );
a58a12e9 352
139adb6a
RR
353 m_xScrollPixelsPerLine = pixelsPerUnitX;
354 m_yScrollPixelsPerLine = pixelsPerUnitY;
355 m_xScrollPosition = xPos;
356 m_yScrollPosition = yPos;
a91b47e8 357
150c8d89
RL
358 int w = noUnitsX * pixelsPerUnitX;
359 int h = noUnitsY * pixelsPerUnitY;
360
2b5f62a0
VZ
361 // For better backward compatibility we set persisting limits
362 // here not just the size. It makes SetScrollbars 'sticky'
363 // emulating the old non-autoscroll behaviour.
2b43d588 364 // m_targetWindow->SetVirtualSizeHints( w, h );
a58a12e9 365
2b5f62a0
VZ
366 // The above should arguably be deprecated, this however we still need.
367
f18f464c
VZ
368 // take care not to set 0 virtual size, 0 means that we don't have any
369 // scrollbars and hence we should use the real size instead of the virtual
370 // one which is indicated by using wxDefaultCoord
371 m_targetWindow->SetVirtualSize( w ? w : wxDefaultCoord,
372 h ? h : wxDefaultCoord);
dc429f89 373
a58a12e9 374 if (do_refresh && !noRefresh)
ca65c044 375 m_targetWindow->Refresh(true, GetScrollRect());
a58a12e9 376
1f066698
VZ
377#ifndef __WXUNIVERSAL__
378 // If the target is not the same as the window with the scrollbars,
379 // then we need to update the scrollbars here, since they won't have
380 // been updated by SetVirtualSize().
381 if ( m_targetWindow != m_win )
382#endif // !__WXUNIVERSAL__
383 {
384 AdjustScrollbars();
385 }
386#ifndef __WXUNIVERSAL__
387 else
388 {
389 // otherwise this has been done by AdjustScrollbars, above
1f066698
VZ
390 }
391#endif // !__WXUNIVERSAL__
c801d85f
KB
392}
393
d80cd92a 394// ----------------------------------------------------------------------------
af4088f1 395// [target] window handling
d80cd92a 396// ----------------------------------------------------------------------------
ecab4dba 397
349efbaa 398void wxScrollHelper::DeleteEvtHandler()
ecab4dba 399{
248d771c
VZ
400 // search for m_handler in the handler list
401 if ( m_win && m_handler )
349efbaa 402 {
74f6bbf9 403 if ( m_win->RemoveEventHandler(m_handler) )
248d771c 404 {
74f6bbf9 405 delete m_handler;
248d771c 406 }
74f6bbf9
VZ
407 //else: something is very wrong, so better [maybe] leak memory than
408 // risk a crash because of double deletion
248d771c 409
74f6bbf9 410 m_handler = NULL;
349efbaa
VZ
411 }
412}
413
af4088f1 414void wxScrollHelper::DoSetTargetWindow(wxWindow *target)
349efbaa 415{
ecab4dba 416 m_targetWindow = target;
8adc196b
SC
417#ifdef __WXMAC__
418 target->MacSetClipChildren( true ) ;
419#endif
349efbaa
VZ
420
421 // install the event handler which will intercept the events we're
af4088f1
VZ
422 // interested in (but only do it for our real window, not the target window
423 // which we scroll - we don't need to hijack its events)
424 if ( m_targetWindow == m_win )
13ff9344 425 {
248d771c
VZ
426 // if we already have a handler, delete it first
427 DeleteEvtHandler();
428
13ff9344
JS
429 m_handler = new wxScrollHelperEvtHandler(this);
430 m_targetWindow->PushEventHandler(m_handler);
431 }
349efbaa
VZ
432}
433
af4088f1 434void wxScrollHelper::SetTargetWindow(wxWindow *target)
349efbaa
VZ
435{
436 wxCHECK_RET( target, wxT("target window must not be NULL") );
437
438 if ( target == m_targetWindow )
439 return;
440
af4088f1 441 DoSetTargetWindow(target);
ecab4dba
RR
442}
443
1e6feb95 444wxWindow *wxScrollHelper::GetTargetWindow() const
ecab4dba
RR
445{
446 return m_targetWindow;
447}
448
d80cd92a
VZ
449// ----------------------------------------------------------------------------
450// scrolling implementation itself
451// ----------------------------------------------------------------------------
452
1e6feb95 453void wxScrollHelper::HandleOnScroll(wxScrollWinEvent& event)
c801d85f 454{
139adb6a 455 int nScrollInc = CalcScrollInc(event);
1e6feb95 456 if ( nScrollInc == 0 )
139adb6a 457 {
1e6feb95
VZ
458 // can't scroll further
459 event.Skip();
460
461 return;
139adb6a 462 }
c801d85f 463
1e6feb95 464 int orient = event.GetOrientation();
139adb6a
RR
465 if (orient == wxHORIZONTAL)
466 {
467 m_xScrollPosition += nScrollInc;
5f3286d1 468 m_win->SetScrollPos(wxHORIZONTAL, m_xScrollPosition);
139adb6a 469 }
c801d85f 470 else
139adb6a
RR
471 {
472 m_yScrollPosition += nScrollInc;
5f3286d1 473 m_win->SetScrollPos(wxVERTICAL, m_yScrollPosition);
139adb6a 474 }
a58a12e9 475
ca65c044 476 bool needsRefresh = false;
1e6feb95
VZ
477 int dx = 0,
478 dy = 0;
139adb6a
RR
479 if (orient == wxHORIZONTAL)
480 {
1e6feb95
VZ
481 if ( m_xScrollingEnabled )
482 {
483 dx = -m_xScrollPixelsPerLine * nScrollInc;
484 }
139adb6a 485 else
1e6feb95 486 {
ca65c044 487 needsRefresh = true;
1e6feb95 488 }
139adb6a 489 }
c801d85f 490 else
139adb6a 491 {
1e6feb95
VZ
492 if ( m_yScrollingEnabled )
493 {
494 dy = -m_yScrollPixelsPerLine * nScrollInc;
495 }
139adb6a 496 else
1e6feb95 497 {
ca65c044 498 needsRefresh = true;
1e6feb95
VZ
499 }
500 }
501
502 if ( needsRefresh )
503 {
ca65c044 504 m_targetWindow->Refresh(true, GetScrollRect());
1e6feb95
VZ
505 }
506 else
507 {
d5d58a93 508 m_targetWindow->ScrollWindow(dx, dy, GetScrollRect());
3d2b9c20 509 }
c801d85f
KB
510}
511
1e6feb95 512int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event)
c801d85f 513{
ecab4dba
RR
514 int pos = event.GetPosition();
515 int orient = event.GetOrientation();
c801d85f 516
ecab4dba 517 int nScrollInc = 0;
1a8caf94 518 if (event.GetEventType() == wxEVT_SCROLLWIN_TOP)
c801d85f 519 {
ecab4dba
RR
520 if (orient == wxHORIZONTAL)
521 nScrollInc = - m_xScrollPosition;
522 else
523 nScrollInc = - m_yScrollPosition;
1a8caf94
RR
524 } else
525 if (event.GetEventType() == wxEVT_SCROLLWIN_BOTTOM)
526 {
ecab4dba
RR
527 if (orient == wxHORIZONTAL)
528 nScrollInc = m_xScrollLines - m_xScrollPosition;
529 else
530 nScrollInc = m_yScrollLines - m_yScrollPosition;
1a8caf94
RR
531 } else
532 if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP)
533 {
ecab4dba 534 nScrollInc = -1;
1a8caf94
RR
535 } else
536 if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN)
537 {
ecab4dba 538 nScrollInc = 1;
1a8caf94
RR
539 } else
540 if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEUP)
541 {
ecab4dba
RR
542 if (orient == wxHORIZONTAL)
543 nScrollInc = -GetScrollPageSize(wxHORIZONTAL);
544 else
545 nScrollInc = -GetScrollPageSize(wxVERTICAL);
1a8caf94
RR
546 } else
547 if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEDOWN)
548 {
ecab4dba
RR
549 if (orient == wxHORIZONTAL)
550 nScrollInc = GetScrollPageSize(wxHORIZONTAL);
551 else
552 nScrollInc = GetScrollPageSize(wxVERTICAL);
1a8caf94
RR
553 } else
554 if ((event.GetEventType() == wxEVT_SCROLLWIN_THUMBTRACK) ||
555 (event.GetEventType() == wxEVT_SCROLLWIN_THUMBRELEASE))
556 {
ecab4dba
RR
557 if (orient == wxHORIZONTAL)
558 nScrollInc = pos - m_xScrollPosition;
559 else
560 nScrollInc = pos - m_yScrollPosition;
c801d85f 561 }
88150e60 562
ecab4dba
RR
563 if (orient == wxHORIZONTAL)
564 {
a58a12e9 565 if (m_xScrollPixelsPerLine > 0)
ecab4dba 566 {
878ddad5
RR
567 if ( m_xScrollPosition + nScrollInc < 0 )
568 {
569 // As -ve as we can go
570 nScrollInc = -m_xScrollPosition;
571 }
572 else // check for the other bound
573 {
574 const int posMax = m_xScrollLines - m_xScrollLinesPerPage;
575 if ( m_xScrollPosition + nScrollInc > posMax )
576 {
577 // As +ve as we can go
578 nScrollInc = posMax - m_xScrollPosition;
579 }
580 }
ecab4dba
RR
581 }
582 else
ca65c044 583 m_targetWindow->Refresh(true, GetScrollRect());
9d9355c6
VZ
584 }
585 else
ecab4dba 586 {
be9b0663 587 if ( m_yScrollPixelsPerLine > 0 )
d80cd92a 588 {
be9b0663
VZ
589 if ( m_yScrollPosition + nScrollInc < 0 )
590 {
591 // As -ve as we can go
592 nScrollInc = -m_yScrollPosition;
593 }
594 else // check for the other bound
595 {
596 const int posMax = m_yScrollLines - m_yScrollLinesPerPage;
597 if ( m_yScrollPosition + nScrollInc > posMax )
598 {
599 // As +ve as we can go
600 nScrollInc = posMax - m_yScrollPosition;
601 }
602 }
ecab4dba
RR
603 }
604 else
be9b0663
VZ
605 {
606 // VZ: why do we do this? (FIXME)
ca65c044 607 m_targetWindow->Refresh(true, GetScrollRect());
be9b0663 608 }
9d9355c6 609 }
9d9355c6 610
ecab4dba 611 return nScrollInc;
c801d85f
KB
612}
613
614// Adjust the scrollbars - new version.
1e6feb95 615void wxScrollHelper::AdjustScrollbars()
c801d85f 616{
2a201ef8
VZ
617 static wxRecursionGuardFlag s_flagReentrancy;
618 wxRecursionGuard guard(s_flagReentrancy);
619 if ( guard.IsInside() )
620 {
621 // don't reenter AdjustScrollbars() while another call to
622 // AdjustScrollbars() is in progress because this may lead to calling
623 // ScrollWindow() twice and this can really happen under MSW if
624 // SetScrollbar() call below adds or removes the scrollbar which
625 // changes the window size and hence results in another
626 // AdjustScrollbars() call
627 return;
628 }
629
566d84a7
RL
630 int w = 0, h = 0;
631 int oldw, oldh;
a58a12e9 632
27d029c7
RR
633 int oldXScroll = m_xScrollPosition;
634 int oldYScroll = m_yScrollPosition;
c801d85f 635
be9b0663
VZ
636 // VZ: at least under Windows this loop is useless because when scrollbars
637 // [dis]appear we get a WM_SIZE resulting in another call to
638 // AdjustScrollbars() anyhow. As it doesn't seem to do any harm I leave
639 // it here for now but it would be better to ensure that all ports
640 // generate EVT_SIZE when scrollbars [dis]appear, emulating it if
641 // necessary, and remove it later
870c86bc
JS
642 // JACS: Stop potential infinite loop by limiting number of iterations
643 int iterationCount = 0;
644 const int iterationMax = 5;
be9b0663
VZ
645 do
646 {
870c86bc 647 iterationCount ++;
d32e78bd 648
566d84a7 649 GetTargetSize(&w, 0);
c801d85f 650
878ddad5
RR
651 // scroll lines per page: if 0, no scrolling is needed
652 int linesPerPage;
653
654 if ( m_xScrollPixelsPerLine == 0 )
566d84a7 655 {
878ddad5 656 // scrolling is disabled
566d84a7
RL
657 m_xScrollLines = 0;
658 m_xScrollPosition = 0;
878ddad5 659 linesPerPage = 0;
566d84a7 660 }
878ddad5 661 else // might need scrolling
566d84a7 662 {
878ddad5
RR
663 // Round up integer division to catch any "leftover" client space.
664 const int wVirt = m_targetWindow->GetVirtualSize().GetWidth();
665 m_xScrollLines = (wVirt + m_xScrollPixelsPerLine - 1) / m_xScrollPixelsPerLine;
566d84a7
RL
666
667 // Calculate page size i.e. number of scroll units you get on the
878ddad5
RR
668 // current client window.
669 linesPerPage = w / m_xScrollPixelsPerLine;
670
671 // Special case. When client and virtual size are very close but
672 // the client is big enough, kill scrollbar.
673 if ((linesPerPage < m_xScrollLines) && (w >= wVirt)) ++linesPerPage;
674
675 if (linesPerPage >= m_xScrollLines)
676 {
677 // we're big enough to not need scrolling
678 linesPerPage =
679 m_xScrollLines =
680 m_xScrollPosition = 0;
681 }
682 else // we do need a scrollbar
683 {
684 if ( linesPerPage < 1 )
685 linesPerPage = 1;
686
687 // Correct position if greater than extent of canvas minus
688 // the visible portion of it or if below zero
689 const int posMax = m_xScrollLines - linesPerPage;
690 if ( m_xScrollPosition > posMax )
691 m_xScrollPosition = posMax;
692 else if ( m_xScrollPosition < 0 )
693 m_xScrollPosition = 0;
694 }
566d84a7 695 }
c801d85f 696
878ddad5
RR
697 m_win->SetScrollbar(wxHORIZONTAL, m_xScrollPosition,
698 linesPerPage, m_xScrollLines);
a58a12e9 699
878ddad5
RR
700 // The amount by which we scroll when paging
701 SetScrollPageSize(wxHORIZONTAL, linesPerPage);
702
703 GetTargetSize(0, &h);
be9b0663
VZ
704
705 if ( m_yScrollPixelsPerLine == 0 )
566d84a7 706 {
be9b0663 707 // scrolling is disabled
566d84a7
RL
708 m_yScrollLines = 0;
709 m_yScrollPosition = 0;
be9b0663 710 linesPerPage = 0;
566d84a7 711 }
be9b0663 712 else // might need scrolling
566d84a7 713 {
878ddad5
RR
714 // Round up integer division to catch any "leftover" client space.
715 const int hVirt = m_targetWindow->GetVirtualSize().GetHeight();
716 m_yScrollLines = ( hVirt + m_yScrollPixelsPerLine - 1 ) / m_yScrollPixelsPerLine;
566d84a7
RL
717
718 // Calculate page size i.e. number of scroll units you get on the
878ddad5 719 // current client window.
be9b0663 720 linesPerPage = h / m_yScrollPixelsPerLine;
878ddad5
RR
721
722 // Special case. When client and virtual size are very close but
723 // the client is big enough, kill scrollbar.
724 if ((linesPerPage < m_yScrollLines) && (h >= hVirt)) ++linesPerPage;
725
726 if (linesPerPage >= m_yScrollLines)
be9b0663
VZ
727 {
728 // we're big enough to not need scrolling
729 linesPerPage =
730 m_yScrollLines =
731 m_yScrollPosition = 0;
732 }
733 else // we do need a scrollbar
734 {
735 if ( linesPerPage < 1 )
736 linesPerPage = 1;
737
738 // Correct position if greater than extent of canvas minus
739 // the visible portion of it or if below zero
740 const int posMax = m_yScrollLines - linesPerPage;
741 if ( m_yScrollPosition > posMax )
742 m_yScrollPosition = posMax;
743 else if ( m_yScrollPosition < 0 )
744 m_yScrollPosition = 0;
745 }
746 }
566d84a7 747
be9b0663
VZ
748 m_win->SetScrollbar(wxVERTICAL, m_yScrollPosition,
749 linesPerPage, m_yScrollLines);
566d84a7 750
be9b0663
VZ
751 // The amount by which we scroll when paging
752 SetScrollPageSize(wxVERTICAL, linesPerPage);
c801d85f 753
139adb6a 754
be9b0663 755 // If a scrollbar (dis)appeared as a result of this, adjust them again.
566d84a7
RL
756 oldw = w;
757 oldh = h;
758
759 GetTargetSize( &w, &h );
870c86bc 760 } while ( (w != oldw || h != oldh) && (iterationCount < iterationMax) );
566d84a7
RL
761
762#ifdef __WXMOTIF__
763 // Sorry, some Motif-specific code to implement a backing pixmap
764 // for the wxRETAINED style. Implementing a backing store can't
765 // be entirely generic because it relies on the wxWindowDC implementation
766 // to duplicate X drawing calls for the backing pixmap.
767
768 if ( m_targetWindow->GetWindowStyle() & wxRETAINED )
139adb6a 769 {
566d84a7
RL
770 Display* dpy = XtDisplay((Widget)m_targetWindow->GetMainWidget());
771
772 int totalPixelWidth = m_xScrollLines * m_xScrollPixelsPerLine;
773 int totalPixelHeight = m_yScrollLines * m_yScrollPixelsPerLine;
774 if (m_targetWindow->GetBackingPixmap() &&
775 !((m_targetWindow->GetPixmapWidth() == totalPixelWidth) &&
776 (m_targetWindow->GetPixmapHeight() == totalPixelHeight)))
777 {
778 XFreePixmap (dpy, (Pixmap) m_targetWindow->GetBackingPixmap());
779 m_targetWindow->SetBackingPixmap((WXPixmap) 0);
780 }
781
782 if (!m_targetWindow->GetBackingPixmap() &&
9b66c26a 783 (m_xScrollLines != 0) && (m_yScrollLines != 0))
566d84a7
RL
784 {
785 int depth = wxDisplayDepth();
786 m_targetWindow->SetPixmapWidth(totalPixelWidth);
787 m_targetWindow->SetPixmapHeight(totalPixelHeight);
788 m_targetWindow->SetBackingPixmap((WXPixmap) XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
789 m_targetWindow->GetPixmapWidth(), m_targetWindow->GetPixmapHeight(), depth));
790 }
791
139adb6a 792 }
566d84a7 793#endif // Motif
a58a12e9 794
27d029c7
RR
795 if (oldXScroll != m_xScrollPosition)
796 {
797 if (m_xScrollingEnabled)
566d84a7 798 m_targetWindow->ScrollWindow( m_xScrollPixelsPerLine * (oldXScroll - m_xScrollPosition), 0,
d5d58a93 799 GetScrollRect() );
27d029c7 800 else
ca65c044 801 m_targetWindow->Refresh(true, GetScrollRect());
27d029c7 802 }
a58a12e9 803
27d029c7
RR
804 if (oldYScroll != m_yScrollPosition)
805 {
806 if (m_yScrollingEnabled)
1e6feb95 807 m_targetWindow->ScrollWindow( 0, m_yScrollPixelsPerLine * (oldYScroll-m_yScrollPosition),
d5d58a93 808 GetScrollRect() );
27d029c7 809 else
ca65c044 810 m_targetWindow->Refresh(true, GetScrollRect());
27d029c7 811 }
c801d85f
KB
812}
813
1e6feb95 814void wxScrollHelper::DoPrepareDC(wxDC& dc)
c801d85f 815{
1e6feb95
VZ
816 wxPoint pt = dc.GetDeviceOrigin();
817 dc.SetDeviceOrigin( pt.x - m_xScrollPosition * m_xScrollPixelsPerLine,
818 pt.y - m_yScrollPosition * m_yScrollPixelsPerLine );
139adb6a 819 dc.SetUserScale( m_scaleX, m_scaleY );
c801d85f
KB
820}
821
566d84a7
RL
822void wxScrollHelper::SetScrollRate( int xstep, int ystep )
823{
824 int old_x = m_xScrollPixelsPerLine * m_xScrollPosition;
825 int old_y = m_yScrollPixelsPerLine * m_yScrollPosition;
826
827 m_xScrollPixelsPerLine = xstep;
828 m_yScrollPixelsPerLine = ystep;
829
830 int new_x = m_xScrollPixelsPerLine * m_xScrollPosition;
831 int new_y = m_yScrollPixelsPerLine * m_yScrollPosition;
832
833 m_win->SetScrollPos( wxHORIZONTAL, m_xScrollPosition );
834 m_win->SetScrollPos( wxVERTICAL, m_yScrollPosition );
835 m_targetWindow->ScrollWindow( old_x - new_x, old_y - new_y );
836
837 AdjustScrollbars();
838}
839
1e6feb95 840void wxScrollHelper::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const
c801d85f 841{
a0bc2c1d
VZ
842 if ( x_unit )
843 *x_unit = m_xScrollPixelsPerLine;
844 if ( y_unit )
845 *y_unit = m_yScrollPixelsPerLine;
c801d85f
KB
846}
847
1e6feb95 848int wxScrollHelper::GetScrollPageSize(int orient) const
c801d85f
KB
849{
850 if ( orient == wxHORIZONTAL )
851 return m_xScrollLinesPerPage;
852 else
853 return m_yScrollLinesPerPage;
854}
855
1e6feb95 856void wxScrollHelper::SetScrollPageSize(int orient, int pageSize)
c801d85f
KB
857{
858 if ( orient == wxHORIZONTAL )
859 m_xScrollLinesPerPage = pageSize;
860 else
861 m_yScrollLinesPerPage = pageSize;
862}
863
864/*
865 * Scroll to given position (scroll position, not pixel position)
866 */
1e6feb95 867void wxScrollHelper::Scroll( int x_pos, int y_pos )
c801d85f 868{
8b089c5e
JS
869 if (!m_targetWindow)
870 return;
871
a58a12e9 872 if (((x_pos == -1) || (x_pos == m_xScrollPosition)) &&
139adb6a 873 ((y_pos == -1) || (y_pos == m_yScrollPosition))) return;
a58a12e9 874
8d7eaf91 875 int w = 0, h = 0;
1e6feb95 876 GetTargetSize(&w, &h);
c801d85f 877
8775b357 878 if ((x_pos != -1) && (m_xScrollPixelsPerLine))
c801d85f 879 {
ed673c6a 880 int old_x = m_xScrollPosition;
139adb6a 881 m_xScrollPosition = x_pos;
a58a12e9 882
3d2b9c20
RR
883 // Calculate page size i.e. number of scroll units you get on the
884 // current client window
ecab4dba 885 int noPagePositions = (int) ( (w/(double)m_xScrollPixelsPerLine) + 0.5 );
139adb6a
RR
886 if (noPagePositions < 1) noPagePositions = 1;
887
888 // Correct position if greater than extent of canvas minus
3d2b9c20 889 // the visible portion of it or if below zero
139adb6a
RR
890 m_xScrollPosition = wxMin( m_xScrollLines-noPagePositions, m_xScrollPosition );
891 m_xScrollPosition = wxMax( 0, m_xScrollPosition );
a58a12e9 892
f6bcfd97 893 if (old_x != m_xScrollPosition) {
5f3286d1 894 m_win->SetScrollPos( wxHORIZONTAL, m_xScrollPosition );
1e6feb95 895 m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0,
d5d58a93 896 GetScrollRect() );
f6bcfd97 897 }
c801d85f 898 }
8775b357 899 if ((y_pos != -1) && (m_yScrollPixelsPerLine))
c801d85f 900 {
ed673c6a 901 int old_y = m_yScrollPosition;
139adb6a 902 m_yScrollPosition = y_pos;
a58a12e9 903
3d2b9c20
RR
904 // Calculate page size i.e. number of scroll units you get on the
905 // current client window
ecab4dba 906 int noPagePositions = (int) ( (h/(double)m_yScrollPixelsPerLine) + 0.5 );
139adb6a
RR
907 if (noPagePositions < 1) noPagePositions = 1;
908
909 // Correct position if greater than extent of canvas minus
3d2b9c20 910 // the visible portion of it or if below zero
139adb6a
RR
911 m_yScrollPosition = wxMin( m_yScrollLines-noPagePositions, m_yScrollPosition );
912 m_yScrollPosition = wxMax( 0, m_yScrollPosition );
d2c52078 913
f6bcfd97 914 if (old_y != m_yScrollPosition) {
5f3286d1 915 m_win->SetScrollPos( wxVERTICAL, m_yScrollPosition );
1e6feb95 916 m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine,
d5d58a93 917 GetScrollRect() );
f6bcfd97 918 }
c801d85f 919 }
c801d85f
KB
920}
921
1e6feb95 922void wxScrollHelper::EnableScrolling (bool x_scroll, bool y_scroll)
c801d85f 923{
139adb6a
RR
924 m_xScrollingEnabled = x_scroll;
925 m_yScrollingEnabled = y_scroll;
c801d85f
KB
926}
927
c801d85f 928// Where the current view starts from
1e6feb95 929void wxScrollHelper::GetViewStart (int *x, int *y) const
c801d85f 930{
a0bc2c1d
VZ
931 if ( x )
932 *x = m_xScrollPosition;
933 if ( y )
934 *y = m_yScrollPosition;
c801d85f
KB
935}
936
8c2f3797 937void wxScrollHelper::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) const
c801d85f 938{
a0bc2c1d
VZ
939 if ( xx )
940 *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
941 if ( yy )
942 *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine;
c801d85f
KB
943}
944
8c2f3797 945void wxScrollHelper::DoCalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
c801d85f 946{
a0bc2c1d
VZ
947 if ( xx )
948 *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine;
949 if ( yy )
950 *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine;
c801d85f 951}
d80cd92a 952
d32e78bd
VZ
953// ----------------------------------------------------------------------------
954// geometry
955// ----------------------------------------------------------------------------
956
957bool wxScrollHelper::ScrollLayout()
958{
959 if ( m_win->GetSizer() && m_targetWindow == m_win )
960 {
961 // If we're the scroll target, take into account the
962 // virtual size and scrolled position of the window.
963
8d7eaf91 964 int x = 0, y = 0, w = 0, h = 0;
d32e78bd
VZ
965 CalcScrolledPosition(0,0, &x,&y);
966 m_win->GetVirtualSize(&w, &h);
967 m_win->GetSizer()->SetDimension(x, y, w, h);
968 return true;
969 }
970
971 // fall back to default for LayoutConstraints
972 return m_win->wxWindow::Layout();
973}
974
975void wxScrollHelper::ScrollDoSetVirtualSize(int x, int y)
976{
977 m_win->wxWindow::DoSetVirtualSize( x, y );
978 AdjustScrollbars();
979
980 if (m_win->GetAutoLayout())
981 m_win->Layout();
982}
983
984// wxWindow's GetBestVirtualSize returns the actual window size,
985// whereas we want to return the virtual size
986wxSize wxScrollHelper::ScrollGetBestVirtualSize() const
987{
988 wxSize clientSize(m_win->GetClientSize());
989 if ( m_win->GetSizer() )
990 clientSize.IncTo(m_win->GetSizer()->CalcMin());
991
992 return clientSize;
993}
994
995// return the window best size from the given best virtual size
996wxSize
997wxScrollHelper::ScrollGetWindowSizeForVirtualSize(const wxSize& size) const
998{
999 // Only use the content to set the window size in the direction
1000 // where there's no scrolling; otherwise we're going to get a huge
1001 // window in the direction in which scrolling is enabled
1002 int ppuX, ppuY;
1003 GetScrollPixelsPerUnit(&ppuX, &ppuY);
1004
1005 wxSize minSize = m_win->GetMinSize();
1006 if ( !minSize.IsFullySpecified() )
1007 minSize = m_win->GetSize();
1008
1009 wxSize best(size);
1010 if (ppuX > 0)
1011 best.x = minSize.x;
1012 if (ppuY > 0)
1013 best.y = minSize.y;
1014
1015 return best;
1016}
1017
d80cd92a
VZ
1018// ----------------------------------------------------------------------------
1019// event handlers
1020// ----------------------------------------------------------------------------
1021
1022// Default OnSize resets scrollbars, if any
1e6feb95 1023void wxScrollHelper::HandleOnSize(wxSizeEvent& WXUNUSED(event))
d80cd92a 1024{
c376d80f 1025 if ( m_targetWindow->GetAutoLayout() )
2b5f62a0 1026 {
c376d80f 1027 wxSize size = m_targetWindow->GetBestVirtualSize();
d32e78bd 1028
c376d80f 1029 // This will call ::Layout() and ::AdjustScrollbars()
168f82ce 1030 m_win->SetVirtualSize( size );
2b5f62a0
VZ
1031 }
1032 else
c376d80f 1033 {
2b5f62a0 1034 AdjustScrollbars();
c376d80f 1035 }
d80cd92a
VZ
1036}
1037
1038// This calls OnDraw, having adjusted the origin according to the current
1039// scroll position
1e6feb95 1040void wxScrollHelper::HandleOnPaint(wxPaintEvent& WXUNUSED(event))
d80cd92a 1041{
af4088f1
VZ
1042 // don't use m_targetWindow here, this is always called for ourselves
1043 wxPaintDC dc(m_win);
1e6feb95 1044 DoPrepareDC(dc);
d80cd92a
VZ
1045
1046 OnDraw(dc);
1047}
1048
438e3558
VZ
1049// kbd handling: notice that we use OnChar() and not OnKeyDown() for
1050// compatibility here - if we used OnKeyDown(), the programs which process
1051// arrows themselves in their OnChar() would never get the message and like
1052// this they always have the priority
1e6feb95 1053void wxScrollHelper::HandleOnChar(wxKeyEvent& event)
d80cd92a 1054{
8d7eaf91
MW
1055 int stx = 0, sty = 0, // view origin
1056 szx = 0, szy = 0, // view size (total)
1057 clix = 0, cliy = 0; // view size (on screen)
d80cd92a 1058
1e6feb95
VZ
1059 GetViewStart(&stx, &sty);
1060 GetTargetSize(&clix, &cliy);
566d84a7 1061 m_targetWindow->GetVirtualSize(&szx, &szy);
56dade3c
RL
1062
1063 if( m_xScrollPixelsPerLine )
1064 {
1065 clix /= m_xScrollPixelsPerLine;
d7da9756 1066 szx /= m_xScrollPixelsPerLine;
56dade3c
RL
1067 }
1068 else
1069 {
1070 clix = 0;
d7da9756 1071 szx = -1;
56dade3c
RL
1072 }
1073 if( m_yScrollPixelsPerLine )
1074 {
1075 cliy /= m_yScrollPixelsPerLine;
1076 szy /= m_yScrollPixelsPerLine;
1077 }
1078 else
1079 {
1080 cliy = 0;
d7da9756 1081 szy = -1;
56dade3c 1082 }
d80cd92a 1083
39c869a6
VZ
1084 int xScrollOld = m_xScrollPosition,
1085 yScrollOld = m_yScrollPosition;
1086
ecb01792 1087 int dsty;
4995ca80 1088 switch ( event.GetKeyCode() )
d80cd92a
VZ
1089 {
1090 case WXK_PAGEUP:
ecb01792
RL
1091 dsty = sty - (5 * cliy / 6);
1092 Scroll(-1, (dsty == -1) ? 0 : dsty);
d80cd92a
VZ
1093 break;
1094
1095 case WXK_PAGEDOWN:
d80cd92a
VZ
1096 Scroll(-1, sty + (5 * cliy / 6));
1097 break;
1098
d80cd92a
VZ
1099 case WXK_HOME:
1100 Scroll(0, event.ControlDown() ? 0 : -1);
1101 break;
1102
1103 case WXK_END:
4acd108c 1104 Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1);
d80cd92a
VZ
1105 break;
1106
1107 case WXK_UP:
1108 Scroll(-1, sty - 1);
1109 break;
1110
1111 case WXK_DOWN:
1112 Scroll(-1, sty + 1);
1113 break;
1114
1115 case WXK_LEFT:
1116 Scroll(stx - 1, -1);
1117 break;
1118
1119 case WXK_RIGHT:
1120 Scroll(stx + 1, -1);
1121 break;
1122
1123 default:
1124 // not for us
1125 event.Skip();
1126 }
39c869a6
VZ
1127
1128 if ( m_xScrollPosition != xScrollOld )
1129 {
1130 wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_xScrollPosition,
1131 wxHORIZONTAL);
1132 event.SetEventObject(m_win);
1133 m_win->GetEventHandler()->ProcessEvent(event);
1134 }
1135
1136 if ( m_yScrollPosition != yScrollOld )
1137 {
1138 wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_yScrollPosition,
1139 wxVERTICAL);
1140 event.SetEventObject(m_win);
1141 m_win->GetEventHandler()->ProcessEvent(event);
1142 }
d80cd92a 1143}
d2c52078 1144
1e6feb95
VZ
1145// ----------------------------------------------------------------------------
1146// autoscroll stuff: these functions deal with sending fake scroll events when
1147// a captured mouse is being held outside the window
1148// ----------------------------------------------------------------------------
1149
1150bool wxScrollHelper::SendAutoScrollEvents(wxScrollWinEvent& event) const
1151{
1152 // only send the event if the window is scrollable in this direction
1153 wxWindow *win = (wxWindow *)event.GetEventObject();
1154 return win->HasScrollbar(event.GetOrientation());
1155}
1156
1157void wxScrollHelper::StopAutoScrolling()
1158{
4b316329 1159#if wxUSE_TIMER
1e6feb95
VZ
1160 if ( m_timerAutoScroll )
1161 {
1162 delete m_timerAutoScroll;
1163 m_timerAutoScroll = (wxTimer *)NULL;
1164 }
4b316329 1165#endif
1e6feb95 1166}
d2c52078 1167
1e6feb95 1168void wxScrollHelper::HandleOnMouseEnter(wxMouseEvent& event)
d2c52078 1169{
1e6feb95
VZ
1170 StopAutoScrolling();
1171
1172 event.Skip();
1173}
d2c52078 1174
1e6feb95
VZ
1175void wxScrollHelper::HandleOnMouseLeave(wxMouseEvent& event)
1176{
1177 // don't prevent the usual processing of the event from taking place
1178 event.Skip();
1179
1180 // when a captured mouse leave a scrolled window we start generate
1181 // scrolling events to allow, for example, extending selection beyond the
1182 // visible area in some controls
1183 if ( wxWindow::GetCapture() == m_targetWindow )
1184 {
1185 // where is the mouse leaving?
1186 int pos, orient;
1187 wxPoint pt = event.GetPosition();
1188 if ( pt.x < 0 )
1189 {
1190 orient = wxHORIZONTAL;
1191 pos = 0;
1192 }
1193 else if ( pt.y < 0 )
1194 {
1195 orient = wxVERTICAL;
1196 pos = 0;
1197 }
1198 else // we're lower or to the right of the window
1199 {
1200 wxSize size = m_targetWindow->GetClientSize();
1201 if ( pt.x > size.x )
1202 {
1203 orient = wxHORIZONTAL;
1204 pos = m_xScrollLines;
1205 }
1206 else if ( pt.y > size.y )
1207 {
1208 orient = wxVERTICAL;
1209 pos = m_yScrollLines;
1210 }
1211 else // this should be impossible
1212 {
1213 // but seems to happen sometimes under wxMSW - maybe it's a bug
1214 // there but for now just ignore it
1215
1216 //wxFAIL_MSG( _T("can't understand where has mouse gone") );
1217
1218 return;
1219 }
1220 }
1221
1222 // only start the auto scroll timer if the window can be scrolled in
1223 // this direction
1224 if ( !m_targetWindow->HasScrollbar(orient) )
1225 return;
1226
4b316329 1227#if wxUSE_TIMER
1e6feb95
VZ
1228 delete m_timerAutoScroll;
1229 m_timerAutoScroll = new wxAutoScrollTimer
1230 (
1231 m_targetWindow, this,
1232 pos == 0 ? wxEVT_SCROLLWIN_LINEUP
1233 : wxEVT_SCROLLWIN_LINEDOWN,
1234 pos,
1235 orient
1236 );
1237 m_timerAutoScroll->Start(50); // FIXME: make configurable
534b127c
WS
1238#else
1239 wxUnusedVar(pos);
4b316329 1240#endif
1e6feb95
VZ
1241 }
1242}
1243
e421922f
VZ
1244#if wxUSE_MOUSEWHEEL
1245
1e6feb95
VZ
1246void wxScrollHelper::HandleOnMouseWheel(wxMouseEvent& event)
1247{
d2c52078 1248 m_wheelRotation += event.GetWheelRotation();
1e6feb95 1249 int lines = m_wheelRotation / event.GetWheelDelta();
d2c52078
RD
1250 m_wheelRotation -= lines * event.GetWheelDelta();
1251
1e6feb95
VZ
1252 if (lines != 0)
1253 {
1e6feb95 1254
b6b85bdc
JS
1255 wxScrollWinEvent newEvent;
1256
ac6f6ffc 1257 newEvent.SetPosition(0);
b6b85bdc 1258 newEvent.SetOrientation(wxVERTICAL);
687706f5 1259 newEvent.SetEventObject(m_win);
b6b85bdc 1260
9b9337da 1261 if (event.IsPageScroll())
4b056ef5
RD
1262 {
1263 if (lines > 0)
687706f5 1264 newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEUP);
4b056ef5 1265 else
687706f5 1266 newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);
4b056ef5 1267
b6b85bdc 1268 m_win->GetEventHandler()->ProcessEvent(newEvent);
4b056ef5
RD
1269 }
1270 else
1271 {
1272 lines *= event.GetLinesPerAction();
1273 if (lines > 0)
687706f5 1274 newEvent.SetEventType(wxEVT_SCROLLWIN_LINEUP);
4b056ef5 1275 else
687706f5 1276 newEvent.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);
b6b85bdc 1277
4b056ef5
RD
1278 int times = abs(lines);
1279 for (; times > 0; times--)
1280 m_win->GetEventHandler()->ProcessEvent(newEvent);
1281 }
d2c52078
RD
1282 }
1283}
1284
e421922f
VZ
1285#endif // wxUSE_MOUSEWHEEL
1286
1e6feb95 1287// ----------------------------------------------------------------------------
d32e78bd 1288// wxScrolledWindow implementation
1e6feb95
VZ
1289// ----------------------------------------------------------------------------
1290
d32e78bd 1291IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel)
1e6feb95 1292
d32e78bd
VZ
1293BEGIN_EVENT_TABLE(wxScrolledWindow, wxPanel)
1294 EVT_PAINT(wxScrolledWindow::OnPaint)
349efbaa
VZ
1295END_EVENT_TABLE()
1296
d32e78bd 1297bool wxScrolledWindow::Create(wxWindow *parent,
1e6feb95
VZ
1298 wxWindowID id,
1299 const wxPoint& pos,
1300 const wxSize& size,
1301 long style,
1302 const wxString& name)
1303{
1304 m_targetWindow = this;
8adc196b
SC
1305#ifdef __WXMAC__
1306 MacSetClipChildren( true ) ;
1307#endif
1e6feb95 1308
04b6e2f0 1309 bool ok = wxPanel::Create(parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1e6feb95 1310
1e6feb95
VZ
1311 return ok;
1312}
1313
d32e78bd 1314wxScrolledWindow::~wxScrolledWindow()
1e6feb95
VZ
1315{
1316}
d2c52078 1317
d32e78bd 1318void wxScrolledWindow::OnPaint(wxPaintEvent& event)
349efbaa
VZ
1319{
1320 // the user code didn't really draw the window if we got here, so set this
1321 // flag to try to call OnDraw() later
1322 m_handler->ResetDrawnFlag();
1323
1324 event.Skip();
1325}
1326
0cf5b099 1327#ifdef __WXMSW__
d32e78bd 1328WXLRESULT wxScrolledWindow::MSWWindowProc(WXUINT nMsg,
0cf5b099
VZ
1329 WXWPARAM wParam,
1330 WXLPARAM lParam)
1331{
c140b7e7 1332 WXLRESULT rc = wxPanel::MSWWindowProc(nMsg, wParam, lParam);
0cf5b099 1333
4676948b 1334#ifndef __WXWINCE__
0cf5b099
VZ
1335 // we need to process arrows ourselves for scrolling
1336 if ( nMsg == WM_GETDLGCODE )
1337 {
1338 rc |= DLGC_WANTARROWS;
1339 }
4676948b 1340#endif
0cf5b099
VZ
1341
1342 return rc;
1343}
1344
1345#endif // __WXMSW__