1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        generic/scrolwin.cpp 
   3 // Purpose:     wxScrolledWindow implementation 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21     #pragma implementation "scrolwin.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  32 #include "wx/dcclient.h" 
  34 #include "wx/generic/scrolwin.h" 
  42 // For wxRETAINED implementation 
  43 #ifdef __VMS__ //VMS's Xm.h is not (yet) compatible with C++ 
  44                //This code switches off the compiler warnings 
  45 # pragma message disable nosimpint 
  49 # pragma message enable nosimpint 
  53 // ---------------------------------------------------------------------------- 
  55 // ---------------------------------------------------------------------------- 
  57 BEGIN_EVENT_TABLE(wxScrolledWindow
, wxPanel
) 
  58     EVT_SCROLLWIN(wxScrolledWindow::OnScroll
) 
  59     EVT_SIZE(wxScrolledWindow::OnSize
) 
  60     EVT_PAINT(wxScrolledWindow::OnPaint
) 
  61     EVT_CHAR(wxScrolledWindow::OnChar
) 
  64 IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow
, wxPanel
) 
  66 // ============================================================================ 
  68 // ============================================================================ 
  70 // ---------------------------------------------------------------------------- 
  71 // wxScrolledWindow creation 
  72 // ---------------------------------------------------------------------------- 
  74 wxScrolledWindow::wxScrolledWindow() 
  76     m_xScrollPixelsPerLine 
= 0; 
  77     m_yScrollPixelsPerLine 
= 0; 
  78     m_xScrollingEnabled 
= TRUE
; 
  79     m_yScrollingEnabled 
= TRUE
; 
  80     m_xScrollPosition 
= 0; 
  81     m_yScrollPosition 
= 0; 
  84     m_xScrollLinesPerPage 
= 0; 
  85     m_yScrollLinesPerPage 
= 0; 
  88     m_targetWindow 
= (wxWindow
*) NULL
; 
  91 bool wxScrolledWindow::Create(wxWindow 
*parent
, 
  98     m_xScrollPixelsPerLine 
= 0; 
  99     m_yScrollPixelsPerLine 
= 0; 
 100     m_xScrollingEnabled 
= TRUE
; 
 101     m_yScrollingEnabled 
= TRUE
; 
 102     m_xScrollPosition 
= 0; 
 103     m_yScrollPosition 
= 0; 
 106     m_xScrollLinesPerPage 
= 0; 
 107     m_yScrollLinesPerPage 
= 0; 
 111     m_targetWindow 
= this; 
 113     bool ok 
= wxPanel::Create(parent
, id
, pos
, size
, style
, name
); 
 116     // we need to process arrows ourselves for scrolling 
 117     m_lDlgCode 
|= DLGC_WANTARROWS
; 
 123 wxScrolledWindow::~wxScrolledWindow() 
 127 // ---------------------------------------------------------------------------- 
 128 // setting scrolling parameters 
 129 // ---------------------------------------------------------------------------- 
 132  * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line) 
 133  * noUnitsX/noUnitsY:        : no. units per scrollbar 
 135 void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX
, int pixelsPerUnitY
, 
 136                int noUnitsX
, int noUnitsY
, 
 137                int xPos
, int yPos
, bool noRefresh 
) 
 141     CalcUnscrolledPosition(xPos
, yPos
, &xpos
, &ypos
); 
 144       (noUnitsX 
!= 0 && m_xScrollLines 
== 0) || 
 145       (noUnitsX 
< m_xScrollLines 
&& xpos 
> pixelsPerUnitX
*noUnitsX
) ||  
 147       (noUnitsY 
!= 0 && m_yScrollLines 
== 0) || 
 148       (noUnitsY 
< m_yScrollLines 
&& ypos 
> pixelsPerUnitY
*noUnitsY
) || 
 149       (xPos 
!= m_xScrollPosition
) || 
 150       (yPos 
!= m_yScrollPosition
) 
 151 //       (pixelsPerUnitX != m_xScrollPixelsPerLine) || 
 152 //       (pixelsPerUnitY != m_yScrollPixelsPerLine) 
 155     m_xScrollPixelsPerLine 
= pixelsPerUnitX
; 
 156     m_yScrollPixelsPerLine 
= pixelsPerUnitY
; 
 157     m_xScrollPosition 
= xPos
; 
 158     m_yScrollPosition 
= yPos
; 
 159     m_xScrollLines 
= noUnitsX
; 
 160     m_yScrollLines 
= noUnitsY
; 
 163     // Sorry, some Motif-specific code to implement a backing pixmap 
 164     // for the wxRETAINED style. Implementing a backing store can't 
 165     // be entirely generic because it relies on the wxWindowDC implementation 
 166     // to duplicate X drawing calls for the backing pixmap. 
 168     if ((m_windowStyle 
& wxRETAINED
) == wxRETAINED
) 
 170         Display
* dpy 
= XtDisplay((Widget
) GetMainWidget()); 
 172         int totalPixelWidth 
= m_xScrollLines 
* m_xScrollPixelsPerLine
; 
 173         int totalPixelHeight 
= m_yScrollLines 
* m_yScrollPixelsPerLine
; 
 174         if (m_backingPixmap 
&& 
 175            !((m_pixmapWidth 
== totalPixelWidth
) && 
 176              (m_pixmapHeight 
== totalPixelHeight
))) 
 178             XFreePixmap (dpy
, (Pixmap
) m_backingPixmap
); 
 179             m_backingPixmap 
= (WXPixmap
) 0; 
 182         if (!m_backingPixmap 
&& 
 183            (noUnitsX 
!= 0) && (noUnitsY 
!= 0)) 
 185             int depth 
= wxDisplayDepth(); 
 186             m_pixmapWidth 
= totalPixelWidth
; 
 187             m_pixmapHeight 
= totalPixelHeight
; 
 188             m_backingPixmap 
= (WXPixmap
) XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)), 
 189             m_pixmapWidth
, m_pixmapHeight
, depth
); 
 197     if (do_refresh 
&& !noRefresh
) 
 198         m_targetWindow
->Refresh(); 
 201     // GRG: if this turns out to be really necessary, we could 
 202     //   at least move it to the above if { ... } so that it is 
 203     //   only done if noRefresh = FALSE (the default). OTOH, if 
 204     //   this doesn't break anything, which seems to be the 
 205     //   case, we could just leave it out. 
 208     // UpdateWindow ((HWND) m_targetWindow->GetHWND()); 
 211     m_targetWindow
->MacUpdateImmediately() ; 
 215 // ---------------------------------------------------------------------------- 
 216 // target window handling 
 217 // ---------------------------------------------------------------------------- 
 219 void wxScrolledWindow::SetTargetWindow( wxWindow 
*target 
) 
 221     wxASSERT_MSG( target
, wxT("target window must not be NULL") ); 
 222     m_targetWindow 
= target
; 
 225 wxWindow 
*wxScrolledWindow::GetTargetWindow() 
 227     return m_targetWindow
; 
 230 // ---------------------------------------------------------------------------- 
 231 // scrolling implementation itself 
 232 // ---------------------------------------------------------------------------- 
 234 void wxScrolledWindow::OnScroll(wxScrollWinEvent
& event
) 
 236     int orient 
= event
.GetOrientation(); 
 238     int nScrollInc 
= CalcScrollInc(event
); 
 239     if (nScrollInc 
== 0) return; 
 241     if (orient 
== wxHORIZONTAL
) 
 243         int newPos 
= m_xScrollPosition 
+ nScrollInc
; 
 244         SetScrollPos(wxHORIZONTAL
, newPos
, TRUE 
); 
 248         int newPos 
= m_yScrollPosition 
+ nScrollInc
; 
 249         SetScrollPos(wxVERTICAL
, newPos
, TRUE 
); 
 252     if (orient 
== wxHORIZONTAL
) 
 254         m_xScrollPosition 
+= nScrollInc
; 
 258         m_yScrollPosition 
+= nScrollInc
; 
 261     if (orient 
== wxHORIZONTAL
) 
 263        if (m_xScrollingEnabled
) 
 264             m_targetWindow
->ScrollWindow(-m_xScrollPixelsPerLine 
* nScrollInc
, 0, (const wxRect 
*) NULL
); 
 266             m_targetWindow
->Refresh(); 
 270         if (m_yScrollingEnabled
) 
 271             m_targetWindow
->ScrollWindow(0, -m_yScrollPixelsPerLine 
* nScrollInc
, (const wxRect 
*) NULL
); 
 273             m_targetWindow
->Refresh(); 
 276     m_targetWindow
->MacUpdateImmediately() ; 
 280 int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent
& event
) 
 282     int pos 
= event
.GetPosition(); 
 283     int orient 
= event
.GetOrientation(); 
 286     switch (event
.GetEventType()) 
 288         case wxEVT_SCROLLWIN_TOP
: 
 290             if (orient 
== wxHORIZONTAL
) 
 291                 nScrollInc 
= - m_xScrollPosition
; 
 293                 nScrollInc 
= - m_yScrollPosition
; 
 296         case wxEVT_SCROLLWIN_BOTTOM
: 
 298             if (orient 
== wxHORIZONTAL
) 
 299                 nScrollInc 
= m_xScrollLines 
- m_xScrollPosition
; 
 301                 nScrollInc 
= m_yScrollLines 
- m_yScrollPosition
; 
 304         case wxEVT_SCROLLWIN_LINEUP
: 
 309         case wxEVT_SCROLLWIN_LINEDOWN
: 
 314         case wxEVT_SCROLLWIN_PAGEUP
: 
 316             if (orient 
== wxHORIZONTAL
) 
 317                 nScrollInc 
= -GetScrollPageSize(wxHORIZONTAL
); 
 319                 nScrollInc 
= -GetScrollPageSize(wxVERTICAL
); 
 322         case wxEVT_SCROLLWIN_PAGEDOWN
: 
 324             if (orient 
== wxHORIZONTAL
) 
 325                 nScrollInc 
= GetScrollPageSize(wxHORIZONTAL
); 
 327                 nScrollInc 
= GetScrollPageSize(wxVERTICAL
); 
 330         case wxEVT_SCROLLWIN_THUMBTRACK
: 
 331         case wxEVT_SCROLLWIN_THUMBRELEASE
: 
 333             if (orient 
== wxHORIZONTAL
) 
 334                 nScrollInc 
= pos 
- m_xScrollPosition
; 
 336                 nScrollInc 
= pos 
- m_yScrollPosition
; 
 345     if (orient 
== wxHORIZONTAL
) 
 347         if (m_xScrollPixelsPerLine 
> 0) 
 350             m_targetWindow
->GetClientSize(&w
, &h
); 
 352             int nMaxWidth 
= m_xScrollLines
*m_xScrollPixelsPerLine
; 
 353             int noPositions 
= (int) ( ((nMaxWidth 
- w
)/(double)m_xScrollPixelsPerLine
) + 0.5 ); 
 357             if ( (m_xScrollPosition 
+ nScrollInc
) < 0 ) 
 358                 nScrollInc 
= -m_xScrollPosition
; // As -ve as we can go 
 359             else if ( (m_xScrollPosition 
+ nScrollInc
) > noPositions 
) 
 360                 nScrollInc 
= noPositions 
- m_xScrollPosition
; // As +ve as we can go 
 363             m_targetWindow
->Refresh(); 
 367         if (m_yScrollPixelsPerLine 
> 0) 
 370             m_targetWindow
->GetClientSize(&w
, &h
); 
 372             int nMaxHeight 
= m_yScrollLines
*m_yScrollPixelsPerLine
; 
 373             int noPositions 
= (int) ( ((nMaxHeight 
- h
)/(double)m_yScrollPixelsPerLine
) + 0.5 ); 
 377             if ( (m_yScrollPosition 
+ nScrollInc
) < 0 ) 
 378                 nScrollInc 
= -m_yScrollPosition
; // As -ve as we can go 
 379             else if ( (m_yScrollPosition 
+ nScrollInc
) > noPositions 
) 
 380                 nScrollInc 
= noPositions 
- m_yScrollPosition
; // As +ve as we can go 
 383             m_targetWindow
->Refresh(); 
 389 // Adjust the scrollbars - new version. 
 390 void wxScrolledWindow::AdjustScrollbars() 
 393     m_targetWindow
->GetClientSize(&w
, &h
); 
 395     int oldXScroll 
= m_xScrollPosition
; 
 396     int oldYScroll 
= m_yScrollPosition
; 
 398     if (m_xScrollLines 
> 0) 
 400         // Calculate page size i.e. number of scroll units you get on the 
 401         // current client window 
 402         int noPagePositions 
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 0.5 ); 
 403         if (noPagePositions 
< 1) noPagePositions 
= 1; 
 405         // Correct position if greater than extent of canvas minus 
 406         // the visible portion of it or if below zero 
 407         m_xScrollPosition 
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
); 
 408         m_xScrollPosition 
= wxMax( 0, m_xScrollPosition 
); 
 410         SetScrollbar(wxHORIZONTAL
, m_xScrollPosition
, noPagePositions
, m_xScrollLines
); 
 411         // The amount by which we scroll when paging 
 412         SetScrollPageSize(wxHORIZONTAL
, noPagePositions
); 
 416         m_xScrollPosition 
= 0; 
 417         SetScrollbar (wxHORIZONTAL
, 0, 0, 0, FALSE
); 
 420     if (m_yScrollLines 
> 0) 
 422         // Calculate page size i.e. number of scroll units you get on the 
 423         // current client window 
 424         int noPagePositions 
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 ); 
 425         if (noPagePositions 
< 1) noPagePositions 
= 1; 
 427         // Correct position if greater than extent of canvas minus 
 428         // the visible portion of it or if below zero 
 429         m_yScrollPosition 
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition 
); 
 430         m_yScrollPosition 
= wxMax( 0, m_yScrollPosition 
); 
 432         SetScrollbar(wxVERTICAL
, m_yScrollPosition
, noPagePositions
, m_yScrollLines
); 
 433         // The amount by which we scroll when paging 
 434         SetScrollPageSize(wxVERTICAL
, noPagePositions
); 
 438         m_yScrollPosition 
= 0; 
 439         SetScrollbar (wxVERTICAL
, 0, 0, 0, FALSE
); 
 442     if (oldXScroll 
!= m_xScrollPosition
) 
 444        if (m_xScrollingEnabled
) 
 445             m_targetWindow
->ScrollWindow( m_xScrollPixelsPerLine 
* (oldXScroll
-m_xScrollPosition
), 0, (const wxRect 
*) NULL 
); 
 447             m_targetWindow
->Refresh(); 
 450     if (oldYScroll 
!= m_yScrollPosition
) 
 452         if (m_yScrollingEnabled
) 
 453             m_targetWindow
->ScrollWindow( 0, m_yScrollPixelsPerLine 
* (oldYScroll
-m_yScrollPosition
), (const wxRect 
*) NULL 
); 
 455             m_targetWindow
->Refresh(); 
 459 // Override this function if you don't want to have wxScrolledWindow 
 460 // automatically change the origin according to the scroll position. 
 461 void wxScrolledWindow::PrepareDC(wxDC
& dc
) 
 463     dc
.SetDeviceOrigin( -m_xScrollPosition 
* m_xScrollPixelsPerLine
, 
 464                         -m_yScrollPosition 
* m_yScrollPixelsPerLine 
); 
 465     dc
.SetUserScale( m_scaleX
, m_scaleY 
); 
 468 #if WXWIN_COMPATIBILITY 
 469 void wxScrolledWindow::GetScrollUnitsPerPage (int *x_page
, int *y_page
) const 
 471       *x_page 
= GetScrollPageSize(wxHORIZONTAL
); 
 472       *y_page 
= GetScrollPageSize(wxVERTICAL
); 
 475 void wxScrolledWindow::CalcUnscrolledPosition(int x
, int y
, float *xx
, float *yy
) const 
 478         *xx 
= (float)(x 
+ m_xScrollPosition 
* m_xScrollPixelsPerLine
); 
 480         *yy 
= (float)(y 
+ m_yScrollPosition 
* m_yScrollPixelsPerLine
); 
 482 #endif // WXWIN_COMPATIBILITY 
 484 void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit
, int *y_unit
) const 
 487         *x_unit 
= m_xScrollPixelsPerLine
; 
 489         *y_unit 
= m_yScrollPixelsPerLine
; 
 492 int wxScrolledWindow::GetScrollPageSize(int orient
) const 
 494     if ( orient 
== wxHORIZONTAL 
) 
 495         return m_xScrollLinesPerPage
; 
 497         return m_yScrollLinesPerPage
; 
 500 void wxScrolledWindow::SetScrollPageSize(int orient
, int pageSize
) 
 502     if ( orient 
== wxHORIZONTAL 
) 
 503         m_xScrollLinesPerPage 
= pageSize
; 
 505         m_yScrollLinesPerPage 
= pageSize
; 
 509  * Scroll to given position (scroll position, not pixel position) 
 511 void wxScrolledWindow::Scroll( int x_pos
, int y_pos 
) 
 516     if (((x_pos 
== -1) || (x_pos 
== m_xScrollPosition
)) && 
 517         ((y_pos 
== -1) || (y_pos 
== m_yScrollPosition
))) return; 
 520     m_targetWindow
->GetClientSize(&w
, &h
); 
 522     if ((x_pos 
!= -1) && (m_xScrollPixelsPerLine
)) 
 524         int old_x 
= m_xScrollPosition
; 
 525         m_xScrollPosition 
= x_pos
; 
 527         // Calculate page size i.e. number of scroll units you get on the 
 528         // current client window 
 529         int noPagePositions 
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 0.5 ); 
 530         if (noPagePositions 
< 1) noPagePositions 
= 1; 
 532         // Correct position if greater than extent of canvas minus 
 533         // the visible portion of it or if below zero 
 534         m_xScrollPosition 
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition 
); 
 535         m_xScrollPosition 
= wxMax( 0, m_xScrollPosition 
); 
 537         if (old_x 
!= m_xScrollPosition
) { 
 538             m_targetWindow
->SetScrollPos( wxHORIZONTAL
, m_xScrollPosition
, TRUE 
); 
 539             m_targetWindow
->ScrollWindow( (old_x
-m_xScrollPosition
)*m_xScrollPixelsPerLine
, 0 ); 
 542     if ((y_pos 
!= -1) && (m_yScrollPixelsPerLine
)) 
 544         int old_y 
= m_yScrollPosition
; 
 545         m_yScrollPosition 
= y_pos
; 
 547         // Calculate page size i.e. number of scroll units you get on the 
 548         // current client window 
 549         int noPagePositions 
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 ); 
 550         if (noPagePositions 
< 1) noPagePositions 
= 1; 
 552         // Correct position if greater than extent of canvas minus 
 553         // the visible portion of it or if below zero 
 554         m_yScrollPosition 
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition 
); 
 555         m_yScrollPosition 
= wxMax( 0, m_yScrollPosition 
); 
 557         if (old_y 
!= m_yScrollPosition
) { 
 558             m_targetWindow
->SetScrollPos( wxVERTICAL
, m_yScrollPosition
, TRUE 
); 
 559             m_targetWindow
->ScrollWindow( 0, (old_y
-m_yScrollPosition
)*m_yScrollPixelsPerLine 
); 
 564     m_targetWindow
->MacUpdateImmediately(); 
 568 void wxScrolledWindow::EnableScrolling (bool x_scroll
, bool y_scroll
) 
 570     m_xScrollingEnabled 
= x_scroll
; 
 571     m_yScrollingEnabled 
= y_scroll
; 
 574 void wxScrolledWindow::GetVirtualSize (int *x
, int *y
) const 
 577         *x 
= m_xScrollPixelsPerLine 
* m_xScrollLines
; 
 579         *y 
= m_yScrollPixelsPerLine 
* m_yScrollLines
; 
 582 // Where the current view starts from 
 583 void wxScrolledWindow::GetViewStart (int *x
, int *y
) const 
 586         *x 
= m_xScrollPosition
; 
 588         *y 
= m_yScrollPosition
; 
 591 void wxScrolledWindow::CalcScrolledPosition(int x
, int y
, int *xx
, int *yy
) const 
 594         *xx 
= x 
- m_xScrollPosition 
* m_xScrollPixelsPerLine
; 
 596         *yy 
= y 
- m_yScrollPosition 
* m_yScrollPixelsPerLine
; 
 599 void wxScrolledWindow::CalcUnscrolledPosition(int x
, int y
, int *xx
, int *yy
) const 
 602         *xx 
= x 
+ m_xScrollPosition 
* m_xScrollPixelsPerLine
; 
 604         *yy 
= y 
+ m_yScrollPosition 
* m_yScrollPixelsPerLine
; 
 607 // ---------------------------------------------------------------------------- 
 609 // ---------------------------------------------------------------------------- 
 611 // Default OnSize resets scrollbars, if any 
 612 void wxScrolledWindow::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
 614 #if wxUSE_CONSTRAINTS 
 622 // This calls OnDraw, having adjusted the origin according to the current 
 624 void wxScrolledWindow::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 632 // kbd handling: notice that we use OnChar() and not OnKeyDown() for 
 633 // compatibility here - if we used OnKeyDown(), the programs which process 
 634 // arrows themselves in their OnChar() would never get the message and like 
 635 // this they always have the priority 
 636 void wxScrolledWindow::OnChar(wxKeyEvent
& event
) 
 638     int stx
, sty
,       // view origin 
 639         szx
, szy
,       // view size (total) 
 640         clix
, cliy
;     // view size (on screen) 
 642     ViewStart(&stx
, &sty
); 
 643     GetClientSize(&clix
, &cliy
); 
 644     GetVirtualSize(&szx
, &szy
); 
 646     if( m_xScrollPixelsPerLine 
) 
 648         clix 
/= m_xScrollPixelsPerLine
; 
 649         szx 
/= m_xScrollPixelsPerLine
; 
 656     if( m_yScrollPixelsPerLine 
) 
 658         cliy 
/= m_yScrollPixelsPerLine
; 
 659         szy 
/= m_yScrollPixelsPerLine
; 
 668     switch ( event
.KeyCode() ) 
 672             dsty 
= sty 
- (5 * cliy 
/ 6); 
 673             Scroll(-1, (dsty 
== -1) ? 0 : dsty
); 
 678             Scroll(-1, sty 
+ (5 * cliy 
/ 6)); 
 682             Scroll(0, event
.ControlDown() ? 0 : -1); 
 686             Scroll(szx 
- clix
, event
.ControlDown() ? szy 
- cliy 
: -1);