1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/generic/scrlwing.cpp 
   3 // Purpose:     wxScrolledWindow implementation 
   4 // Author:      Julian Smart 
   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. 
   9 // Copyright:   (c) wxWidgets team 
  10 // Licence:     wxWindows licence 
  11 ///////////////////////////////////////////////////////////////////////////// 
  13 // ============================================================================ 
  15 // ============================================================================ 
  17 // ---------------------------------------------------------------------------- 
  19 // ---------------------------------------------------------------------------- 
  21 // For compilers that support precompilation, includes "wx.h". 
  22 #include "wx/wxprec.h" 
  28 #include "wx/scrolwin.h" 
  33     #include "wx/dcclient.h" 
  36     #include "wx/settings.h" 
  40 #include "wx/scrolbar.h" 
  43 #include "wx/recguard.h" 
  46     #include <windows.h> // for DLGC_WANTARROWS 
  47     #include "wx/msw/winundef.h" 
  51 // For wxRETAINED implementation 
  52 #ifdef __VMS__ //VMS's Xm.h is not (yet) compatible with C++ 
  53                //This code switches off the compiler warnings 
  54 # pragma message disable nosimpint 
  58 # pragma message enable nosimpint 
  64         style wxHSCROLL | wxVSCROLL 
  67 // ---------------------------------------------------------------------------- 
  68 // wxScrollHelperEvtHandler: intercept the events from the window and forward 
  69 // them to wxScrollHelper 
  70 // ---------------------------------------------------------------------------- 
  72 class WXDLLEXPORT wxScrollHelperEvtHandler 
: public wxEvtHandler
 
  75     wxScrollHelperEvtHandler(wxScrollHelperBase 
*scrollHelper
) 
  77         m_scrollHelper 
= scrollHelper
; 
  80     virtual bool ProcessEvent(wxEvent
& event
); 
  82     void ResetDrawnFlag() { m_hasDrawnWindow 
= false; } 
  85     wxScrollHelperBase 
*m_scrollHelper
; 
  87     bool m_hasDrawnWindow
; 
  89     wxDECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler
); 
  93 // ---------------------------------------------------------------------------- 
  94 // wxAutoScrollTimer: the timer used to generate a stream of scroll events when 
  95 // a captured mouse is held outside the window 
  96 // ---------------------------------------------------------------------------- 
  98 class wxAutoScrollTimer 
: public wxTimer
 
 101     wxAutoScrollTimer(wxWindow 
*winToScroll
, 
 102                       wxScrollHelperBase 
*scroll
, 
 103                       wxEventType eventTypeToSend
, 
 104                       int pos
, int orient
); 
 106     virtual void Notify(); 
 110     wxScrollHelperBase 
*m_scrollHelper
; 
 111     wxEventType m_eventType
; 
 115     wxDECLARE_NO_COPY_CLASS(wxAutoScrollTimer
); 
 118 // ============================================================================ 
 120 // ============================================================================ 
 122 // ---------------------------------------------------------------------------- 
 124 // ---------------------------------------------------------------------------- 
 126 wxAutoScrollTimer::wxAutoScrollTimer(wxWindow 
*winToScroll
, 
 127                                      wxScrollHelperBase 
*scroll
, 
 128                                      wxEventType eventTypeToSend
, 
 132     m_scrollHelper 
= scroll
; 
 133     m_eventType 
= eventTypeToSend
; 
 138 void wxAutoScrollTimer::Notify() 
 140     // only do all this as long as the window is capturing the mouse 
 141     if ( wxWindow::GetCapture() != m_win 
) 
 145     else // we still capture the mouse, continue generating events 
 147         // first scroll the window if we are allowed to do it 
 148         wxScrollWinEvent 
event1(m_eventType
, m_pos
, m_orient
); 
 149         event1
.SetEventObject(m_win
); 
 150         if ( m_scrollHelper
->SendAutoScrollEvents(event1
) && 
 151                 m_win
->GetEventHandler()->ProcessEvent(event1
) ) 
 153             // and then send a pseudo mouse-move event to refresh the selection 
 154             wxMouseEvent 
event2(wxEVT_MOTION
); 
 155             event2
.SetPosition(wxGetMousePosition()); 
 157             // the mouse event coordinates should be client, not screen as 
 158             // returned by wxGetMousePosition 
 159             wxWindow 
*parentTop 
= m_win
; 
 160             while ( parentTop
->GetParent() ) 
 161                 parentTop 
= parentTop
->GetParent(); 
 162             wxPoint ptOrig 
= parentTop
->GetPosition(); 
 163             event2
.m_x 
-= ptOrig
.x
; 
 164             event2
.m_y 
-= ptOrig
.y
; 
 166             event2
.SetEventObject(m_win
); 
 168             // FIXME: we don't fill in the other members - ok? 
 170             m_win
->GetEventHandler()->ProcessEvent(event2
); 
 172         else // can't scroll further, stop 
 180 // ---------------------------------------------------------------------------- 
 181 // wxScrollHelperEvtHandler 
 182 // ---------------------------------------------------------------------------- 
 184 bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent
& event
) 
 186     wxEventType evType 
= event
.GetEventType(); 
 188     // the explanation of wxEVT_PAINT processing hack: for historic reasons 
 189     // there are 2 ways to process this event in classes deriving from 
 190     // wxScrolledWindow. The user code may 
 192     //  1. override wxScrolledWindow::OnDraw(dc) 
 193     //  2. define its own OnPaint() handler 
 195     // In addition, in wxUniversal wxWindow defines OnPaint() itself and 
 196     // always processes the draw event, so we can't just try the window 
 197     // OnPaint() first and call our HandleOnPaint() if it doesn't process it 
 198     // (the latter would never be called in wxUniversal). 
 200     // So the solution is to have a flag telling us whether the user code drew 
 201     // anything in the window. We set it to true here but reset it to false in 
 202     // wxScrolledWindow::OnPaint() handler (which wouldn't be called if the 
 203     // user code defined OnPaint() in the derived class) 
 204     m_hasDrawnWindow 
= true; 
 206     // Pass it on to the real handler: notice that we must not call 
 207     // ProcessEvent() on this object itself as it wouldn't pass it to the next 
 208     // handler (i.e. the real window) if we're called from a previous handler 
 209     // (as indicated by "process here only" flag being set) and we do want to 
 210     // execute the handler defined in the window we're associated with right 
 211     // now, without waiting until TryAfter() is called from wxEvtHandler. 
 213     // Note that this means that the handler in the window will be called twice 
 214     // if there is a preceding event handler in the chain because we do it from 
 215     // here now and the base class DoTryChain() will also call it itself when 
 216     // we return. But this unfortunately seems unavoidable. 
 217     bool processed 
= m_nextHandler
->ProcessEvent(event
); 
 219     // always process the size events ourselves, even if the user code handles 
 220     // them as well, as we need to AdjustScrollbars() 
 222     // NB: it is important to do it after processing the event in the normal 
 223     //     way as HandleOnSize() may generate a wxEVT_SIZE itself if the 
 224     //     scrollbar[s] (dis)appear and it should be seen by the user code 
 226     if ( evType 
== wxEVT_SIZE 
) 
 228         m_scrollHelper
->HandleOnSize((wxSizeEvent 
&)event
); 
 235         // normally, nothing more to do here - except if it was a paint event 
 236         // which wasn't really processed, then we'll try to call our 
 237         // OnDraw() below (from HandleOnPaint) 
 238         if ( m_hasDrawnWindow 
|| event
.IsCommandEvent() ) 
 244     if ( evType 
== wxEVT_PAINT 
) 
 246         m_scrollHelper
->HandleOnPaint((wxPaintEvent 
&)event
); 
 250     if ( evType 
== wxEVT_CHILD_FOCUS 
) 
 252         m_scrollHelper
->HandleOnChildFocus((wxChildFocusEvent 
&)event
); 
 256     // reset the skipped flag (which might have been set to true in 
 257     // ProcessEvent() above) to be able to test it below 
 258     bool wasSkipped 
= event
.GetSkipped(); 
 262     if ( evType 
== wxEVT_SCROLLWIN_TOP 
|| 
 263          evType 
== wxEVT_SCROLLWIN_BOTTOM 
|| 
 264          evType 
== wxEVT_SCROLLWIN_LINEUP 
|| 
 265          evType 
== wxEVT_SCROLLWIN_LINEDOWN 
|| 
 266          evType 
== wxEVT_SCROLLWIN_PAGEUP 
|| 
 267          evType 
== wxEVT_SCROLLWIN_PAGEDOWN 
|| 
 268          evType 
== wxEVT_SCROLLWIN_THUMBTRACK 
|| 
 269          evType 
== wxEVT_SCROLLWIN_THUMBRELEASE 
) 
 271         m_scrollHelper
->HandleOnScroll((wxScrollWinEvent 
&)event
); 
 272         if ( !event
.GetSkipped() ) 
 274             // it makes sense to indicate that we processed the message as we 
 275             // did scroll the window (and also notice that wxAutoScrollTimer 
 276             // relies on our return value to stop scrolling when we are at top 
 277             // or bottom already) 
 283     if ( evType 
== wxEVT_ENTER_WINDOW 
) 
 285         m_scrollHelper
->HandleOnMouseEnter((wxMouseEvent 
&)event
); 
 287     else if ( evType 
== wxEVT_LEAVE_WINDOW 
) 
 289         m_scrollHelper
->HandleOnMouseLeave((wxMouseEvent 
&)event
); 
 292     // Use GTK's own scroll wheel handling in GtkScrolledWindow 
 294     else if ( evType 
== wxEVT_MOUSEWHEEL 
) 
 296         m_scrollHelper
->HandleOnMouseWheel((wxMouseEvent 
&)event
); 
 300 #endif // wxUSE_MOUSEWHEEL 
 301     else if ( evType 
== wxEVT_CHAR 
) 
 303         m_scrollHelper
->HandleOnChar((wxKeyEvent 
&)event
); 
 304         if ( !event
.GetSkipped() ) 
 311     event
.Skip(wasSkipped
); 
 316 // ============================================================================ 
 317 // wxScrollHelperBase implementation 
 318 // ============================================================================ 
 320 // ---------------------------------------------------------------------------- 
 321 // wxScrollHelperBase construction 
 322 // ---------------------------------------------------------------------------- 
 324 wxScrollHelperBase::wxScrollHelperBase(wxWindow 
*win
) 
 326     wxASSERT_MSG( win
, wxT("associated window can't be NULL in wxScrollHelper") ); 
 328     m_xScrollPixelsPerLine 
= 
 329     m_yScrollPixelsPerLine 
= 
 334     m_xScrollLinesPerPage 
= 
 335     m_yScrollLinesPerPage 
= 0; 
 337     m_xScrollingEnabled 
= 
 338     m_yScrollingEnabled 
= true; 
 347     m_targetWindow 
= NULL
; 
 349     m_timerAutoScroll 
= NULL
; 
 355     m_win
->SetScrollHelper(static_cast<wxScrollHelper 
*>(this)); 
 357     // by default, the associated window is also the target window 
 358     DoSetTargetWindow(win
); 
 361 wxScrollHelperBase::~wxScrollHelperBase() 
 368 // ---------------------------------------------------------------------------- 
 369 // setting scrolling parameters 
 370 // ---------------------------------------------------------------------------- 
 372 void wxScrollHelperBase::SetScrollbars(int pixelsPerUnitX
, 
 382     CalcUnscrolledPosition(xPos
, yPos
, &xpos
, &ypos
); 
 385       (noUnitsX 
!= 0 && m_xScrollLines 
== 0) || 
 386       (noUnitsX 
< m_xScrollLines 
&& xpos 
> pixelsPerUnitX 
* noUnitsX
) || 
 388       (noUnitsY 
!= 0 && m_yScrollLines 
== 0) || 
 389       (noUnitsY 
< m_yScrollLines 
&& ypos 
> pixelsPerUnitY 
* noUnitsY
) || 
 390       (xPos 
!= m_xScrollPosition
) || 
 391       (yPos 
!= m_yScrollPosition
) 
 394     m_xScrollPixelsPerLine 
= pixelsPerUnitX
; 
 395     m_yScrollPixelsPerLine 
= pixelsPerUnitY
; 
 396     m_xScrollPosition 
= xPos
; 
 397     m_yScrollPosition 
= yPos
; 
 399     int w 
= noUnitsX 
* pixelsPerUnitX
; 
 400     int h 
= noUnitsY 
* pixelsPerUnitY
; 
 402     // For better backward compatibility we set persisting limits 
 403     // here not just the size.  It makes SetScrollbars 'sticky' 
 404     // emulating the old non-autoscroll behaviour. 
 405     //   m_targetWindow->SetVirtualSizeHints( w, h ); 
 407     // The above should arguably be deprecated, this however we still need. 
 409     // take care not to set 0 virtual size, 0 means that we don't have any 
 410     // scrollbars and hence we should use the real size instead of the virtual 
 411     // one which is indicated by using wxDefaultCoord 
 412     m_targetWindow
->SetVirtualSize( w 
? w 
: wxDefaultCoord
, 
 413                                     h 
? h 
: wxDefaultCoord
); 
 415     if (do_refresh 
&& !noRefresh
) 
 416         m_targetWindow
->Refresh(true, GetScrollRect()); 
 418 #ifndef __WXUNIVERSAL__ 
 419     // If the target is not the same as the window with the scrollbars, 
 420     // then we need to update the scrollbars here, since they won't have 
 421     // been updated by SetVirtualSize(). 
 422     if ( m_targetWindow 
!= m_win 
) 
 423 #endif // !__WXUNIVERSAL__ 
 427 #ifndef __WXUNIVERSAL__ 
 430         // otherwise this has been done by AdjustScrollbars, above 
 432 #endif // !__WXUNIVERSAL__ 
 435 // ---------------------------------------------------------------------------- 
 436 // [target] window handling 
 437 // ---------------------------------------------------------------------------- 
 439 void wxScrollHelperBase::DeleteEvtHandler() 
 441     // search for m_handler in the handler list 
 442     if ( m_win 
&& m_handler 
) 
 444         if ( m_win
->RemoveEventHandler(m_handler
) ) 
 448         //else: something is very wrong, so better [maybe] leak memory than 
 449         //      risk a crash because of double deletion 
 455 void wxScrollHelperBase::ResetDrawnFlag() 
 457     wxCHECK_RET( m_handler
, "invalid use of ResetDrawnFlag - no handler?" ); 
 458     m_handler
->ResetDrawnFlag(); 
 461 void wxScrollHelperBase::DoSetTargetWindow(wxWindow 
*target
) 
 463     m_targetWindow 
= target
; 
 465     target
->MacSetClipChildren( true ) ; 
 468     // install the event handler which will intercept the events we're 
 469     // interested in (but only do it for our real window, not the target window 
 470     // which we scroll - we don't need to hijack its events) 
 471     if ( m_targetWindow 
== m_win 
) 
 473         // if we already have a handler, delete it first 
 476         m_handler 
= new wxScrollHelperEvtHandler(this); 
 477         m_targetWindow
->PushEventHandler(m_handler
); 
 481 void wxScrollHelperBase::SetTargetWindow(wxWindow 
*target
) 
 483     wxCHECK_RET( target
, wxT("target window must not be NULL") ); 
 485     if ( target 
== m_targetWindow 
) 
 488     DoSetTargetWindow(target
); 
 491 wxWindow 
*wxScrollHelperBase::GetTargetWindow() const 
 493     return m_targetWindow
; 
 496 // ---------------------------------------------------------------------------- 
 497 // scrolling implementation itself 
 498 // ---------------------------------------------------------------------------- 
 500 void wxScrollHelperBase::HandleOnScroll(wxScrollWinEvent
& event
) 
 502     int nScrollInc 
= CalcScrollInc(event
); 
 503     if ( nScrollInc 
== 0 ) 
 505         // can't scroll further 
 511     bool needsRefresh 
= false; 
 514     int orient 
= event
.GetOrientation(); 
 515     if (orient 
== wxHORIZONTAL
) 
 517        if ( m_xScrollingEnabled 
) 
 519            dx 
= -m_xScrollPixelsPerLine 
* nScrollInc
; 
 528         if ( m_yScrollingEnabled 
) 
 530             dy 
= -m_yScrollPixelsPerLine 
* nScrollInc
; 
 540         // flush all pending repaints before we change m_{x,y}ScrollPosition, as 
 541         // otherwise invalidated area could be updated incorrectly later when 
 542         // ScrollWindow() makes sure they're repainted before scrolling them 
 544         // wxWindowMac is taking care of making sure the update area is correctly 
 545         // set up, while not forcing an immediate redraw 
 547         m_targetWindow
->Update(); 
 551     if (orient 
== wxHORIZONTAL
) 
 553         m_xScrollPosition 
+= nScrollInc
; 
 554         m_win
->SetScrollPos(wxHORIZONTAL
, m_xScrollPosition
); 
 558         m_yScrollPosition 
+= nScrollInc
; 
 559         m_win
->SetScrollPos(wxVERTICAL
, m_yScrollPosition
); 
 564         m_targetWindow
->Refresh(true, GetScrollRect()); 
 568         m_targetWindow
->ScrollWindow(dx
, dy
, GetScrollRect()); 
 572 int wxScrollHelperBase::CalcScrollInc(wxScrollWinEvent
& event
) 
 574     int pos 
= event
.GetPosition(); 
 575     int orient 
= event
.GetOrientation(); 
 578     if (event
.GetEventType() == wxEVT_SCROLLWIN_TOP
) 
 580             if (orient 
== wxHORIZONTAL
) 
 581                 nScrollInc 
= - m_xScrollPosition
; 
 583                 nScrollInc 
= - m_yScrollPosition
; 
 585     if (event
.GetEventType() == wxEVT_SCROLLWIN_BOTTOM
) 
 587             if (orient 
== wxHORIZONTAL
) 
 588                 nScrollInc 
= m_xScrollLines 
- m_xScrollPosition
; 
 590                 nScrollInc 
= m_yScrollLines 
- m_yScrollPosition
; 
 592     if (event
.GetEventType() == wxEVT_SCROLLWIN_LINEUP
) 
 596     if (event
.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN
) 
 600     if (event
.GetEventType() == wxEVT_SCROLLWIN_PAGEUP
) 
 602             if (orient 
== wxHORIZONTAL
) 
 603                 nScrollInc 
= -GetScrollPageSize(wxHORIZONTAL
); 
 605                 nScrollInc 
= -GetScrollPageSize(wxVERTICAL
); 
 607     if (event
.GetEventType() == wxEVT_SCROLLWIN_PAGEDOWN
) 
 609             if (orient 
== wxHORIZONTAL
) 
 610                 nScrollInc 
= GetScrollPageSize(wxHORIZONTAL
); 
 612                 nScrollInc 
= GetScrollPageSize(wxVERTICAL
); 
 614     if ((event
.GetEventType() == wxEVT_SCROLLWIN_THUMBTRACK
) || 
 615         (event
.GetEventType() == wxEVT_SCROLLWIN_THUMBRELEASE
)) 
 617             if (orient 
== wxHORIZONTAL
) 
 618                 nScrollInc 
= pos 
- m_xScrollPosition
; 
 620                 nScrollInc 
= pos 
- m_yScrollPosition
; 
 623     if (orient 
== wxHORIZONTAL
) 
 625         if ( m_xScrollPosition 
+ nScrollInc 
< 0 ) 
 627             // As -ve as we can go 
 628             nScrollInc 
= -m_xScrollPosition
; 
 630         else // check for the other bound 
 632             const int posMax 
= m_xScrollLines 
- m_xScrollLinesPerPage
; 
 633             if ( m_xScrollPosition 
+ nScrollInc 
> posMax 
) 
 635                 // As +ve as we can go 
 636                 nScrollInc 
= posMax 
- m_xScrollPosition
; 
 642         if ( m_yScrollPosition 
+ nScrollInc 
< 0 ) 
 644             // As -ve as we can go 
 645             nScrollInc 
= -m_yScrollPosition
; 
 647         else // check for the other bound 
 649             const int posMax 
= m_yScrollLines 
- m_yScrollLinesPerPage
; 
 650             if ( m_yScrollPosition 
+ nScrollInc 
> posMax 
) 
 652                 // As +ve as we can go 
 653                 nScrollInc 
= posMax 
- m_yScrollPosition
; 
 661 void wxScrollHelperBase::DoPrepareDC(wxDC
& dc
) 
 663     wxPoint pt 
= dc
.GetDeviceOrigin(); 
 665     // It may actually be correct to always query 
 666     // the m_sign from the DC here, but I leave the 
 667     // #ifdef GTK for now. 
 668     if (m_win
->GetLayoutDirection() == wxLayout_RightToLeft
) 
 669         dc
.SetDeviceOrigin( pt
.x 
+ m_xScrollPosition 
* m_xScrollPixelsPerLine
, 
 670                             pt
.y 
- m_yScrollPosition 
* m_yScrollPixelsPerLine 
); 
 673         dc
.SetDeviceOrigin( pt
.x 
- m_xScrollPosition 
* m_xScrollPixelsPerLine
, 
 674                             pt
.y 
- m_yScrollPosition 
* m_yScrollPixelsPerLine 
); 
 675     dc
.SetUserScale( m_scaleX
, m_scaleY 
); 
 678 void wxScrollHelperBase::SetScrollRate( int xstep
, int ystep 
) 
 680     int old_x 
= m_xScrollPixelsPerLine 
* m_xScrollPosition
; 
 681     int old_y 
= m_yScrollPixelsPerLine 
* m_yScrollPosition
; 
 683     m_xScrollPixelsPerLine 
= xstep
; 
 684     m_yScrollPixelsPerLine 
= ystep
; 
 686     int new_x 
= m_xScrollPixelsPerLine 
* m_xScrollPosition
; 
 687     int new_y 
= m_yScrollPixelsPerLine 
* m_yScrollPosition
; 
 689     m_win
->SetScrollPos( wxHORIZONTAL
, m_xScrollPosition 
); 
 690     m_win
->SetScrollPos( wxVERTICAL
, m_yScrollPosition 
); 
 691     m_targetWindow
->ScrollWindow( old_x 
- new_x
, old_y 
- new_y 
); 
 696 void wxScrollHelperBase::GetScrollPixelsPerUnit (int *x_unit
, int *y_unit
) const 
 699         *x_unit 
= m_xScrollPixelsPerLine
; 
 701         *y_unit 
= m_yScrollPixelsPerLine
; 
 705 int wxScrollHelperBase::GetScrollLines( int orient 
) const 
 707     if ( orient 
== wxHORIZONTAL 
) 
 708         return m_xScrollLines
; 
 710         return m_yScrollLines
; 
 713 int wxScrollHelperBase::GetScrollPageSize(int orient
) const 
 715     if ( orient 
== wxHORIZONTAL 
) 
 716         return m_xScrollLinesPerPage
; 
 718         return m_yScrollLinesPerPage
; 
 721 void wxScrollHelperBase::SetScrollPageSize(int orient
, int pageSize
) 
 723     if ( orient 
== wxHORIZONTAL 
) 
 724         m_xScrollLinesPerPage 
= pageSize
; 
 726         m_yScrollLinesPerPage 
= pageSize
; 
 729 void wxScrollHelperBase::EnableScrolling (bool x_scroll
, bool y_scroll
) 
 731     m_xScrollingEnabled 
= x_scroll
; 
 732     m_yScrollingEnabled 
= y_scroll
; 
 735 // Where the current view starts from 
 736 void wxScrollHelperBase::DoGetViewStart (int *x
, int *y
) const 
 739         *x 
= m_xScrollPosition
; 
 741         *y 
= m_yScrollPosition
; 
 744 void wxScrollHelperBase::DoCalcScrolledPosition(int x
, int y
, 
 745                                                 int *xx
, int *yy
) const 
 748         *xx 
= x 
- m_xScrollPosition 
* m_xScrollPixelsPerLine
; 
 750         *yy 
= y 
- m_yScrollPosition 
* m_yScrollPixelsPerLine
; 
 753 void wxScrollHelperBase::DoCalcUnscrolledPosition(int x
, int y
, 
 754                                                   int *xx
, int *yy
) const 
 757         *xx 
= x 
+ m_xScrollPosition 
* m_xScrollPixelsPerLine
; 
 759         *yy 
= y 
+ m_yScrollPosition 
* m_yScrollPixelsPerLine
; 
 762 // ---------------------------------------------------------------------------- 
 764 // ---------------------------------------------------------------------------- 
 766 bool wxScrollHelperBase::ScrollLayout() 
 768     if ( m_win
->GetSizer() && m_targetWindow 
== m_win 
) 
 770         // If we're the scroll target, take into account the 
 771         // virtual size and scrolled position of the window. 
 773         int x 
= 0, y 
= 0, w 
= 0, h 
= 0; 
 774         CalcScrolledPosition(0,0, &x
,&y
); 
 775         m_win
->GetVirtualSize(&w
, &h
); 
 776         m_win
->GetSizer()->SetDimension(x
, y
, w
, h
); 
 780     // fall back to default for LayoutConstraints 
 781     return m_win
->wxWindow::Layout(); 
 784 void wxScrollHelperBase::ScrollDoSetVirtualSize(int x
, int y
) 
 786     m_win
->wxWindow::DoSetVirtualSize( x
, y 
); 
 789     if (m_win
->GetAutoLayout()) 
 793 // wxWindow's GetBestVirtualSize returns the actual window size, 
 794 // whereas we want to return the virtual size 
 795 wxSize 
wxScrollHelperBase::ScrollGetBestVirtualSize() const 
 797     wxSize 
clientSize(m_win
->GetClientSize()); 
 798     if ( m_win
->GetSizer() ) 
 799         clientSize
.IncTo(m_win
->GetSizer()->CalcMin()); 
 804 // ---------------------------------------------------------------------------- 
 806 // ---------------------------------------------------------------------------- 
 808 // Default OnSize resets scrollbars, if any 
 809 void wxScrollHelperBase::HandleOnSize(wxSizeEvent
& WXUNUSED(event
)) 
 811     if ( m_targetWindow
->GetAutoLayout() ) 
 813         wxSize size 
= m_targetWindow
->GetBestVirtualSize(); 
 815         // This will call ::Layout() and ::AdjustScrollbars() 
 816         m_win
->SetVirtualSize( size 
); 
 824 // This calls OnDraw, having adjusted the origin according to the current 
 826 void wxScrollHelperBase::HandleOnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 828     // don't use m_targetWindow here, this is always called for ourselves 
 835 // kbd handling: notice that we use OnChar() and not OnKeyDown() for 
 836 // compatibility here - if we used OnKeyDown(), the programs which process 
 837 // arrows themselves in their OnChar() would never get the message and like 
 838 // this they always have the priority 
 839 void wxScrollHelperBase::HandleOnChar(wxKeyEvent
& event
) 
 841     // prepare the event this key press maps to 
 842     wxScrollWinEvent newEvent
; 
 844     newEvent
.SetPosition(0); 
 845     newEvent
.SetEventObject(m_win
); 
 847     // this is the default, it's changed to wxHORIZONTAL below if needed 
 848     newEvent
.SetOrientation(wxVERTICAL
); 
 850     // some key events result in scrolling in both horizontal and vertical 
 851     // direction, e.g. Ctrl-{Home,End}, if this flag is true we should generate 
 852     // a second event in horizontal direction in addition to the primary one 
 853     bool sendHorizontalToo 
= false; 
 855     switch ( event
.GetKeyCode() ) 
 858             newEvent
.SetEventType(wxEVT_SCROLLWIN_PAGEUP
); 
 862             newEvent
.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN
); 
 866             newEvent
.SetEventType(wxEVT_SCROLLWIN_TOP
); 
 868             sendHorizontalToo 
= event
.ControlDown(); 
 872             newEvent
.SetEventType(wxEVT_SCROLLWIN_BOTTOM
); 
 874             sendHorizontalToo 
= event
.ControlDown(); 
 878             newEvent
.SetOrientation(wxHORIZONTAL
); 
 882             newEvent
.SetEventType(wxEVT_SCROLLWIN_LINEUP
); 
 886             newEvent
.SetOrientation(wxHORIZONTAL
); 
 890             newEvent
.SetEventType(wxEVT_SCROLLWIN_LINEDOWN
); 
 894             // not a scrolling key 
 899     m_win
->ProcessWindowEvent(newEvent
); 
 901     if ( sendHorizontalToo 
) 
 903         newEvent
.SetOrientation(wxHORIZONTAL
); 
 904         m_win
->ProcessWindowEvent(newEvent
); 
 908 // ---------------------------------------------------------------------------- 
 909 // autoscroll stuff: these functions deal with sending fake scroll events when 
 910 // a captured mouse is being held outside the window 
 911 // ---------------------------------------------------------------------------- 
 913 bool wxScrollHelperBase::SendAutoScrollEvents(wxScrollWinEvent
& event
) const 
 915     // only send the event if the window is scrollable in this direction 
 916     wxWindow 
*win 
= (wxWindow 
*)event
.GetEventObject(); 
 917     return win
->HasScrollbar(event
.GetOrientation()); 
 920 void wxScrollHelperBase::StopAutoScrolling() 
 923     if ( m_timerAutoScroll 
) 
 925         delete m_timerAutoScroll
; 
 926         m_timerAutoScroll 
= NULL
; 
 931 void wxScrollHelperBase::HandleOnMouseEnter(wxMouseEvent
& event
) 
 938 void wxScrollHelperBase::HandleOnMouseLeave(wxMouseEvent
& event
) 
 940     // don't prevent the usual processing of the event from taking place 
 943     // when a captured mouse leave a scrolled window we start generate 
 944     // scrolling events to allow, for example, extending selection beyond the 
 945     // visible area in some controls 
 946     if ( wxWindow::GetCapture() == m_targetWindow 
) 
 948         // where is the mouse leaving? 
 950         wxPoint pt 
= event
.GetPosition(); 
 953             orient 
= wxHORIZONTAL
; 
 961         else // we're lower or to the right of the window 
 963             wxSize size 
= m_targetWindow
->GetClientSize(); 
 966                 orient 
= wxHORIZONTAL
; 
 967                 pos 
= m_xScrollLines
; 
 969             else if ( pt
.y 
> size
.y 
) 
 972                 pos 
= m_yScrollLines
; 
 974             else // this should be impossible 
 976                 // but seems to happen sometimes under wxMSW - maybe it's a bug 
 977                 // there but for now just ignore it 
 979                 //wxFAIL_MSG( wxT("can't understand where has mouse gone") ); 
 985         // only start the auto scroll timer if the window can be scrolled in 
 987         if ( !m_targetWindow
->HasScrollbar(orient
) ) 
 991         delete m_timerAutoScroll
; 
 992         m_timerAutoScroll 
= new wxAutoScrollTimer
 
 994                                     m_targetWindow
, this, 
 995                                     pos 
== 0 ? wxEVT_SCROLLWIN_LINEUP
 
 996                                              : wxEVT_SCROLLWIN_LINEDOWN
, 
1000         m_timerAutoScroll
->Start(50); // FIXME: make configurable 
1007 #if wxUSE_MOUSEWHEEL 
1009 void wxScrollHelperBase::HandleOnMouseWheel(wxMouseEvent
& event
) 
1011     m_wheelRotation 
+= event
.GetWheelRotation(); 
1012     int lines 
= m_wheelRotation 
/ event
.GetWheelDelta(); 
1013     m_wheelRotation 
-= lines 
* event
.GetWheelDelta(); 
1018         wxScrollWinEvent newEvent
; 
1020         newEvent
.SetPosition(0); 
1021         newEvent
.SetOrientation( event
.GetWheelAxis() == 0 ? wxVERTICAL 
: wxHORIZONTAL
); 
1022         newEvent
.SetEventObject(m_win
); 
1024         if (event
.IsPageScroll()) 
1027                 newEvent
.SetEventType(wxEVT_SCROLLWIN_PAGEUP
); 
1029                 newEvent
.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN
); 
1031             m_win
->GetEventHandler()->ProcessEvent(newEvent
); 
1035             lines 
*= event
.GetLinesPerAction(); 
1037                 newEvent
.SetEventType(wxEVT_SCROLLWIN_LINEUP
); 
1039                 newEvent
.SetEventType(wxEVT_SCROLLWIN_LINEDOWN
); 
1041             int times 
= abs(lines
); 
1042             for (; times 
> 0; times
--) 
1043                 m_win
->GetEventHandler()->ProcessEvent(newEvent
); 
1048 #endif // wxUSE_MOUSEWHEEL 
1050 void wxScrollHelperBase::HandleOnChildFocus(wxChildFocusEvent
& event
) 
1052     // this event should be processed by all windows in parenthood chain, 
1053     // e.g. so that nested wxScrolledWindows work correctly 
1056     // find the immediate child under which the window receiving focus is: 
1057     wxWindow 
*win 
= event
.GetWindow(); 
1059     if ( win 
== m_targetWindow 
) 
1060         return; // nothing to do 
1062 #if defined( __WXOSX__ ) && wxUSE_SCROLLBAR 
1063     if (wxDynamicCast(win
, wxScrollBar
)) 
1067     // Fixing ticket: http://trac.wxwidgets.org/ticket/9563 
1068     // When a child inside a wxControlContainer receives a focus, the 
1069     // wxControlContainer generates an artificial wxChildFocusEvent for 
1070     // itself, telling its parent that 'it' received the focus. The effect is 
1071     // that this->HandleOnChildFocus is called twice, first with the 
1072     // artificial wxChildFocusEvent and then with the original event.  We need 
1073     // to ignore the artificial event here or otherwise HandleOnChildFocus 
1074     // would first scroll the target window to make the entire 
1075     // wxControlContainer visible and immediately afterwards scroll the target 
1076     // window again to make the child widget visible. This leads to ugly 
1077     // flickering when using nested wxPanels/wxScrolledWindows. 
1079     // Ignore this event if 'win' is derived from wxControlContainer AND its 
1080     // parent is the m_targetWindow AND 'win' is not actually reciving the 
1081     // focus (win != FindFocus).  TODO: This affects all wxControlContainer 
1082     // objects, but wxControlContainer is not part of the wxWidgets RTTI and 
1083     // so wxDynamicCast(win, wxControlContainer) does not compile.  Find a way 
1084     // to determine if 'win' derives from wxControlContainer. Until then, 
1085     // testing if 'win' derives from wxPanel will probably get >90% of all 
1088     wxWindow 
*actual_focus
=wxWindow::FindFocus(); 
1089     if (win 
!= actual_focus 
&& 
1090         wxDynamicCast(win
, wxPanel
) != 0 && 
1091         win
->GetParent() == m_targetWindow
) 
1092         // if win is a wxPanel and receives the focus, it should not be 
1093         // scrolled into view 
1096     const wxRect 
viewRect(m_targetWindow
->GetClientRect()); 
1098     // For composite controls such as wxComboCtrl we should try to fit the 
1099     // entire control inside the visible area of the target window, not just 
1100     // the focused child of the control. Otherwise we'd make only the textctrl 
1101     // part of a wxComboCtrl visible and the button would still be outside the 
1102     // scrolled area.  But do so only if the parent fits *entirely* inside the 
1103     // scrolled window. In other situations, such as nested wxPanel or 
1104     // wxScrolledWindows, the parent might be way to big to fit inside the 
1105     // scrolled window. If that is the case, then make only the focused window 
1107     if ( win
->GetParent() != m_targetWindow
) 
1109         wxWindow 
*parent
=win
->GetParent(); 
1110         wxSize parent_size
=parent
->GetSize(); 
1111         if (parent_size
.GetWidth() <= viewRect
.GetWidth() && 
1112             parent_size
.GetHeight() <= viewRect
.GetHeight()) 
1113             // make the immediate parent visible instead of the focused control 
1117     // make win position relative to the m_targetWindow viewing area instead of 
1120         winRect(m_targetWindow
->ScreenToClient(win
->GetScreenPosition()), 
1123     // check if it's fully visible 
1124     if ( viewRect
.Contains(winRect
) ) 
1126         // it is, nothing to do 
1130     // check if we can make it fully visible: this is only possible if it's not 
1131     // larger than our view area 
1132     if ( winRect
.GetWidth() > viewRect
.GetWidth() || 
1133             winRect
.GetHeight() > viewRect
.GetHeight() ) 
1135         // we can't make it fit so avoid scrolling it at all, this is only 
1136         // going to be confusing and not helpful 
1141     // do make the window fit inside the view area by scrolling to it 
1143     GetScrollPixelsPerUnit(&stepx
, &stepy
); 
1146     GetViewStart(&startx
, &starty
); 
1148     // first in vertical direction: 
1153         if ( winRect
.GetTop() < 0 ) 
1155             diff 
= winRect
.GetTop(); 
1157         else if ( winRect
.GetBottom() > viewRect
.GetHeight() ) 
1159             diff 
= winRect
.GetBottom() - viewRect
.GetHeight() + 1; 
1160             // round up to next scroll step if we can't get exact position, 
1161             // so that the window is fully visible: 
1165         starty 
= (starty 
* stepy 
+ diff
) / stepy
; 
1173         if ( winRect
.GetLeft() < 0 ) 
1175             diff 
= winRect
.GetLeft(); 
1177         else if ( winRect
.GetRight() > viewRect
.GetWidth() ) 
1179             diff 
= winRect
.GetRight() - viewRect
.GetWidth() + 1; 
1180             // round up to next scroll step if we can't get exact position, 
1181             // so that the window is fully visible: 
1185         startx 
= (startx 
* stepx 
+ diff
) / stepx
; 
1188     Scroll(startx
, starty
); 
1192 #ifdef wxHAS_GENERIC_SCROLLWIN 
1194 // ---------------------------------------------------------------------------- 
1195 // wxScrollHelper implementation 
1196 // ---------------------------------------------------------------------------- 
1198 wxScrollHelper::wxScrollHelper(wxWindow 
*winToScroll
) 
1199     : wxScrollHelperBase(winToScroll
) 
1202     m_yVisibility 
= wxSHOW_SB_DEFAULT
; 
1205 void wxScrollHelper::DoShowScrollbars(wxScrollbarVisibility horz
, 
1206                                       wxScrollbarVisibility vert
) 
1208     if ( horz 
!= m_xVisibility 
|| vert 
!= m_yVisibility 
) 
1210         m_xVisibility 
= horz
; 
1211         m_yVisibility 
= vert
; 
1218 wxScrollHelper::DoAdjustScrollbar(int orient
, 
1223                                   int& scrollPosition
, 
1224                                   int& scrollLinesPerPage
, 
1225                                   wxScrollbarVisibility visibility
) 
1227     // scroll lines per page: if 0, no scrolling is needed 
1228     // check if we need scrollbar in this direction at all 
1229     if ( pixelsPerUnit 
== 0 || clientSize 
>= virtSize 
) 
1231         // scrolling is disabled or unnecessary 
1234         scrollLinesPerPage 
= 0; 
1236     else // might need scrolling 
1238         // Round up integer division to catch any "leftover" client space. 
1239         scrollUnits 
= (virtSize 
+ pixelsPerUnit 
- 1) / pixelsPerUnit
; 
1241         // Calculate the number of fully scroll units 
1242         scrollLinesPerPage 
= clientSize 
/ pixelsPerUnit
; 
1244         if ( scrollLinesPerPage 
>= scrollUnits 
) 
1246             // we're big enough to not need scrolling 
1249             scrollLinesPerPage 
= 0; 
1251         else // we do need a scrollbar 
1253             if ( scrollLinesPerPage 
< 1 ) 
1254                 scrollLinesPerPage 
= 1; 
1256             // Correct position if greater than extent of canvas minus 
1257             // the visible portion of it or if below zero 
1258             const int posMax 
= scrollUnits 
- scrollLinesPerPage
; 
1259             if ( scrollPosition 
> posMax 
) 
1260                 scrollPosition 
= posMax
; 
1261             else if ( scrollPosition 
< 0 ) 
1266     // in wxSHOW_SB_NEVER case don't show the scrollbar even if it's needed, in 
1267     // wxSHOW_SB_ALWAYS case show the scrollbar even if it's not needed by 
1268     // passing a special range value to SetScrollbar() 
1270     switch ( visibility 
) 
1272         case wxSHOW_SB_NEVER
: 
1276         case wxSHOW_SB_ALWAYS
: 
1277             range 
= scrollUnits 
? scrollUnits 
: -1; 
1281             wxFAIL_MSG( wxS("unknown scrollbar visibility") ); 
1284         case wxSHOW_SB_DEFAULT
: 
1285             range 
= scrollUnits
; 
1290     m_win
->SetScrollbar(orient
, scrollPosition
, scrollLinesPerPage
, range
); 
1293 void wxScrollHelper::AdjustScrollbars() 
1295     static wxRecursionGuardFlag s_flagReentrancy
; 
1296     wxRecursionGuard 
guard(s_flagReentrancy
); 
1297     if ( guard
.IsInside() ) 
1299         // don't reenter AdjustScrollbars() while another call to 
1300         // AdjustScrollbars() is in progress because this may lead to calling 
1301         // ScrollWindow() twice and this can really happen under MSW if 
1302         // SetScrollbar() call below adds or removes the scrollbar which 
1303         // changes the window size and hence results in another 
1304         // AdjustScrollbars() call 
1308     int oldXScroll 
= m_xScrollPosition
; 
1309     int oldYScroll 
= m_yScrollPosition
; 
1311     // we may need to readjust the scrollbars several times as enabling one of 
1312     // them reduces the area available for the window contents and so can make 
1313     // the other scrollbar necessary now although it wasn't necessary before 
1315     // VZ: normally this loop should be over in at most 2 iterations, I don't 
1316     //     know why do we need 5 of them 
1317     for ( int iterationCount 
= 0; iterationCount 
< 5; iterationCount
++ ) 
1319         wxSize clientSize 
= GetTargetSize(); 
1320         const wxSize virtSize 
= m_targetWindow
->GetVirtualSize(); 
1322         // this block of code tries to work around the following problem: the 
1323         // window could have been just resized to have enough space to show its 
1324         // full contents without the scrollbars, but its client size could be 
1325         // not big enough because it does have the scrollbars right now and so 
1326         // the scrollbars would remain even though we don't need them any more 
1328         // to prevent this from happening, check if we have enough space for 
1329         // everything without the scrollbars and explicitly disable them then 
1330         const wxSize availSize 
= GetSizeAvailableForScrollTarget( 
1331             m_win
->GetSize() - m_win
->GetWindowBorderSize()); 
1332         if ( availSize 
!= clientSize 
) 
1334             if ( availSize
.x 
>= virtSize
.x 
&& availSize
.y 
>= virtSize
.y 
) 
1336                 // this will be enough to make the scrollbars disappear below 
1337                 // and then the client size will indeed become equal to the 
1338                 // full available size 
1339                 clientSize 
= availSize
; 
1344         DoAdjustScrollbar(wxHORIZONTAL
, 
1347                           m_xScrollPixelsPerLine
, 
1350                           m_xScrollLinesPerPage
, 
1353         DoAdjustScrollbar(wxVERTICAL
, 
1356                           m_yScrollPixelsPerLine
, 
1359                           m_yScrollLinesPerPage
, 
1363         // If a scrollbar (dis)appeared as a result of this, we need to adjust 
1364         // them again but if the client size didn't change, then we're done 
1365         if ( GetTargetSize() == clientSize 
) 
1370     // Sorry, some Motif-specific code to implement a backing pixmap 
1371     // for the wxRETAINED style. Implementing a backing store can't 
1372     // be entirely generic because it relies on the wxWindowDC implementation 
1373     // to duplicate X drawing calls for the backing pixmap. 
1375     if ( m_targetWindow
->GetWindowStyle() & wxRETAINED 
) 
1377         Display
* dpy 
= XtDisplay((Widget
)m_targetWindow
->GetMainWidget()); 
1379         int totalPixelWidth 
= m_xScrollLines 
* m_xScrollPixelsPerLine
; 
1380         int totalPixelHeight 
= m_yScrollLines 
* m_yScrollPixelsPerLine
; 
1381         if (m_targetWindow
->GetBackingPixmap() && 
1382            !((m_targetWindow
->GetPixmapWidth() == totalPixelWidth
) && 
1383              (m_targetWindow
->GetPixmapHeight() == totalPixelHeight
))) 
1385             XFreePixmap (dpy
, (Pixmap
) m_targetWindow
->GetBackingPixmap()); 
1386             m_targetWindow
->SetBackingPixmap((WXPixmap
) 0); 
1389         if (!m_targetWindow
->GetBackingPixmap() && 
1390            (m_xScrollLines 
!= 0) && (m_yScrollLines 
!= 0)) 
1392             int depth 
= wxDisplayDepth(); 
1393             m_targetWindow
->SetPixmapWidth(totalPixelWidth
); 
1394             m_targetWindow
->SetPixmapHeight(totalPixelHeight
); 
1395             m_targetWindow
->SetBackingPixmap((WXPixmap
) XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)), 
1396               m_targetWindow
->GetPixmapWidth(), m_targetWindow
->GetPixmapHeight(), depth
)); 
1402     if (oldXScroll 
!= m_xScrollPosition
) 
1404        if (m_xScrollingEnabled
) 
1405             m_targetWindow
->ScrollWindow( m_xScrollPixelsPerLine 
* (oldXScroll 
- m_xScrollPosition
), 0, 
1408             m_targetWindow
->Refresh(true, GetScrollRect()); 
1411     if (oldYScroll 
!= m_yScrollPosition
) 
1413         if (m_yScrollingEnabled
) 
1414             m_targetWindow
->ScrollWindow( 0, m_yScrollPixelsPerLine 
* (oldYScroll
-m_yScrollPosition
), 
1417             m_targetWindow
->Refresh(true, GetScrollRect()); 
1421 void wxScrollHelper::DoScroll( int x_pos
, int y_pos 
) 
1423     if (!m_targetWindow
) 
1426     if (((x_pos 
== -1) || (x_pos 
== m_xScrollPosition
)) && 
1427         ((y_pos 
== -1) || (y_pos 
== m_yScrollPosition
))) return; 
1430     GetTargetSize(&w
, &h
); 
1432     // compute new position: 
1433     int new_x 
= m_xScrollPosition
; 
1434     int new_y 
= m_yScrollPosition
; 
1436     if ((x_pos 
!= -1) && (m_xScrollPixelsPerLine
)) 
1440         // Calculate page size i.e. number of scroll units you get on the 
1441         // current client window 
1442         int noPagePositions 
= w
/m_xScrollPixelsPerLine
; 
1443         if (noPagePositions 
< 1) noPagePositions 
= 1; 
1445         // Correct position if greater than extent of canvas minus 
1446         // the visible portion of it or if below zero 
1447         new_x 
= wxMin( m_xScrollLines
-noPagePositions
, new_x 
); 
1448         new_x 
= wxMax( 0, new_x 
); 
1450     if ((y_pos 
!= -1) && (m_yScrollPixelsPerLine
)) 
1454         // Calculate page size i.e. number of scroll units you get on the 
1455         // current client window 
1456         int noPagePositions 
= h
/m_yScrollPixelsPerLine
; 
1457         if (noPagePositions 
< 1) noPagePositions 
= 1; 
1459         // Correct position if greater than extent of canvas minus 
1460         // the visible portion of it or if below zero 
1461         new_y 
= wxMin( m_yScrollLines
-noPagePositions
, new_y 
); 
1462         new_y 
= wxMax( 0, new_y 
); 
1465     if ( new_x 
== m_xScrollPosition 
&& new_y 
== m_yScrollPosition 
) 
1466         return; // nothing to do, the position didn't change 
1468     // flush all pending repaints before we change m_{x,y}ScrollPosition, as 
1469     // otherwise invalidated area could be updated incorrectly later when 
1470     // ScrollWindow() makes sure they're repainted before scrolling them 
1471     m_targetWindow
->Update(); 
1473     // update the position and scroll the window now: 
1474     if (m_xScrollPosition 
!= new_x
) 
1476         int old_x 
= m_xScrollPosition
; 
1477         m_xScrollPosition 
= new_x
; 
1478         m_win
->SetScrollPos( wxHORIZONTAL
, new_x 
); 
1479         m_targetWindow
->ScrollWindow( (old_x
-new_x
)*m_xScrollPixelsPerLine
, 0, 
1483     if (m_yScrollPosition 
!= new_y
) 
1485         int old_y 
= m_yScrollPosition
; 
1486         m_yScrollPosition 
= new_y
; 
1487         m_win
->SetScrollPos( wxVERTICAL
, new_y 
); 
1488         m_targetWindow
->ScrollWindow( 0, (old_y
-new_y
)*m_yScrollPixelsPerLine
, 
1493 #endif // wxHAS_GENERIC_SCROLLWIN 
1495 // ---------------------------------------------------------------------------- 
1496 // wxScrolled<T> and wxScrolledWindow implementation 
1497 // ---------------------------------------------------------------------------- 
1499 wxSize 
wxScrolledT_Helper::FilterBestSize(const wxWindow 
*win
, 
1500                                           const wxScrollHelper 
*helper
, 
1501                                           const wxSize
& origBest
) 
1503     // NB: We don't do this in WX_FORWARD_TO_SCROLL_HELPER, because not 
1504     //     all scrollable windows should behave like this, only those that 
1505     //     contain children controls within scrollable area 
1506     //     (i.e., wxScrolledWindow) and other some scrollable windows may 
1507     //     have different DoGetBestSize() implementation (e.g. wxTreeCtrl). 
1509     wxSize best 
= origBest
; 
1511     if ( win
->GetAutoLayout() ) 
1513         // Only use the content to set the window size in the direction 
1514         // where there's no scrolling; otherwise we're going to get a huge 
1515         // window in the direction in which scrolling is enabled 
1517         helper
->GetScrollPixelsPerUnit(&ppuX
, &ppuY
); 
1519         // NB: This code used to use *current* size if min size wasn't 
1520         //     specified, presumably to get some reasonable (i.e., larger than 
1521         //     minimal) size.  But that's a wrong thing to do in GetBestSize(), 
1522         //     so we use minimal size as specified. If the app needs some 
1523         //     minimal size for its scrolled window, it should set it and put 
1524         //     the window into sizer as expandable so that it can use all space 
1527         //     See also http://svn.wxwidgets.org/viewvc/wx?view=rev&revision=45864 
1529         wxSize minSize 
= win
->GetMinSize(); 
1532             best
.x 
= minSize
.x 
+ wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
1535             best
.y 
= minSize
.y 
+ wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
1542 WXLRESULT 
wxScrolledT_Helper::FilterMSWWindowProc(WXUINT nMsg
, WXLRESULT rc
) 
1545     // we need to process arrows ourselves for scrolling 
1546     if ( nMsg 
== WM_GETDLGCODE 
) 
1548         rc 
|= DLGC_WANTARROWS
; 
1555 // NB: skipping wxScrolled<T> in wxRTTI information because being a templte, 
1556 //     it doesn't and can't implement wxRTTI support 
1557 IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow
, wxPanel
)