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_KEY_DOWN(wxScrolledWindow::OnKeyDown
)
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;
90 bool wxScrolledWindow::Create(wxWindow
*parent
,
97 m_xScrollPixelsPerLine
= 0;
98 m_yScrollPixelsPerLine
= 0;
99 m_xScrollingEnabled
= TRUE
;
100 m_yScrollingEnabled
= TRUE
;
101 m_xScrollPosition
= 0;
102 m_yScrollPosition
= 0;
105 m_xScrollLinesPerPage
= 0;
106 m_yScrollLinesPerPage
= 0;
110 m_targetWindow
= this;
112 // we need wxWANTS_CHARS to process arrows ourselves
113 return wxPanel::Create(parent
, id
, pos
, size
, style
| wxWANTS_CHARS
, name
);
116 wxScrolledWindow::~wxScrolledWindow()
120 // ----------------------------------------------------------------------------
121 // setting scrolling parameters
122 // ----------------------------------------------------------------------------
125 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
126 * noUnitsX/noUnitsY: : no. units per scrollbar
128 void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX
, int pixelsPerUnitY
,
129 int noUnitsX
, int noUnitsY
,
130 int xPos
, int yPos
, bool noRefresh
)
134 (noUnitsX
!= 0 && m_xScrollLines
== 0) ||
135 (noUnitsX
< m_xScrollLines
) ||
136 (noUnitsY
!= 0 && m_yScrollLines
== 0) ||
137 (noUnitsY
< m_yScrollLines
) ||
138 (xPos
!= m_xScrollPosition
) ||
139 (yPos
!= m_yScrollPosition
) ||
140 (pixelsPerUnitX
!= m_xScrollPixelsPerLine
) ||
141 (pixelsPerUnitY
!= m_yScrollPixelsPerLine
)
144 m_xScrollPixelsPerLine
= pixelsPerUnitX
;
145 m_yScrollPixelsPerLine
= pixelsPerUnitY
;
146 m_xScrollPosition
= xPos
;
147 m_yScrollPosition
= yPos
;
148 m_xScrollLines
= noUnitsX
;
149 m_yScrollLines
= noUnitsY
;
152 // Sorry, some Motif-specific code to implement a backing pixmap
153 // for the wxRETAINED style. Implementing a backing store can't
154 // be entirely generic because it relies on the wxWindowDC implementation
155 // to duplicate X drawing calls for the backing pixmap.
157 if ((m_windowStyle
& wxRETAINED
) == wxRETAINED
)
159 Display
* dpy
= XtDisplay((Widget
) GetMainWidget());
161 int totalPixelWidth
= m_xScrollLines
* m_xScrollPixelsPerLine
;
162 int totalPixelHeight
= m_yScrollLines
* m_yScrollPixelsPerLine
;
163 if (m_backingPixmap
&&
164 !((m_pixmapWidth
== totalPixelWidth
) &&
165 (m_pixmapHeight
== totalPixelHeight
)))
167 XFreePixmap (dpy
, (Pixmap
) m_backingPixmap
);
168 m_backingPixmap
= (WXPixmap
) 0;
171 if (!m_backingPixmap
&&
172 (noUnitsX
!= 0) && (noUnitsY
!= 0))
174 int depth
= wxDisplayDepth();
175 m_pixmapWidth
= totalPixelWidth
;
176 m_pixmapHeight
= totalPixelHeight
;
177 m_backingPixmap
= (WXPixmap
) XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
178 m_pixmapWidth
, m_pixmapHeight
, depth
);
186 if (do_refresh
&& !noRefresh
)
187 m_targetWindow
->Refresh();
190 // GRG: if this turns out to be really necessary, we could
191 // at least move it to the above if { ... } so that it is
192 // only done if noRefresh = FALSE (the default). OTOH, if
193 // this doesn't break anything, which seems to be the
194 // case, we could just leave it out.
197 // UpdateWindow ((HWND) m_targetWindow->GetHWND());
200 m_targetWindow
->MacUpdateImmediately() ;
204 // ----------------------------------------------------------------------------
205 // target window handling
206 // ----------------------------------------------------------------------------
208 void wxScrolledWindow::SetTargetWindow( wxWindow
*target
)
210 wxASSERT_MSG( target
, wxT("target window must not be NULL") );
211 m_targetWindow
= target
;
214 wxWindow
*wxScrolledWindow::GetTargetWindow()
216 return m_targetWindow
;
219 // ----------------------------------------------------------------------------
220 // scrolling implementation itself
221 // ----------------------------------------------------------------------------
223 void wxScrolledWindow::OnScroll(wxScrollWinEvent
& event
)
225 int orient
= event
.GetOrientation();
227 int nScrollInc
= CalcScrollInc(event
);
228 if (nScrollInc
== 0) return;
230 if (orient
== wxHORIZONTAL
)
232 int newPos
= m_xScrollPosition
+ nScrollInc
;
233 SetScrollPos(wxHORIZONTAL
, newPos
, TRUE
);
237 int newPos
= m_yScrollPosition
+ nScrollInc
;
238 SetScrollPos(wxVERTICAL
, newPos
, TRUE
);
241 if (orient
== wxHORIZONTAL
)
243 m_xScrollPosition
+= nScrollInc
;
247 m_yScrollPosition
+= nScrollInc
;
250 if (orient
== wxHORIZONTAL
)
252 if (m_xScrollingEnabled
)
253 m_targetWindow
->ScrollWindow(-m_xScrollPixelsPerLine
* nScrollInc
, 0, (const wxRect
*) NULL
);
255 m_targetWindow
->Refresh();
259 if (m_yScrollingEnabled
)
260 m_targetWindow
->ScrollWindow(0, -m_yScrollPixelsPerLine
* nScrollInc
, (const wxRect
*) NULL
);
262 m_targetWindow
->Refresh();
265 m_targetWindow
->MacUpdateImmediately() ;
269 int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent
& event
)
271 int pos
= event
.GetPosition();
272 int orient
= event
.GetOrientation();
275 switch (event
.GetEventType())
277 case wxEVT_SCROLLWIN_TOP
:
279 if (orient
== wxHORIZONTAL
)
280 nScrollInc
= - m_xScrollPosition
;
282 nScrollInc
= - m_yScrollPosition
;
285 case wxEVT_SCROLLWIN_BOTTOM
:
287 if (orient
== wxHORIZONTAL
)
288 nScrollInc
= m_xScrollLines
- m_xScrollPosition
;
290 nScrollInc
= m_yScrollLines
- m_yScrollPosition
;
293 case wxEVT_SCROLLWIN_LINEUP
:
298 case wxEVT_SCROLLWIN_LINEDOWN
:
303 case wxEVT_SCROLLWIN_PAGEUP
:
305 if (orient
== wxHORIZONTAL
)
306 nScrollInc
= -GetScrollPageSize(wxHORIZONTAL
);
308 nScrollInc
= -GetScrollPageSize(wxVERTICAL
);
311 case wxEVT_SCROLLWIN_PAGEDOWN
:
313 if (orient
== wxHORIZONTAL
)
314 nScrollInc
= GetScrollPageSize(wxHORIZONTAL
);
316 nScrollInc
= GetScrollPageSize(wxVERTICAL
);
319 case wxEVT_SCROLLWIN_THUMBTRACK
:
321 if (orient
== wxHORIZONTAL
)
322 nScrollInc
= pos
- m_xScrollPosition
;
324 nScrollInc
= pos
- m_yScrollPosition
;
333 if (orient
== wxHORIZONTAL
)
335 if (m_xScrollPixelsPerLine
> 0)
338 m_targetWindow
->GetClientSize(&w
, &h
);
340 int nMaxWidth
= m_xScrollLines
*m_xScrollPixelsPerLine
;
341 int noPositions
= (int) ( ((nMaxWidth
- w
)/(double)m_xScrollPixelsPerLine
) + 0.5 );
345 if ( (m_xScrollPosition
+ nScrollInc
) < 0 )
346 nScrollInc
= -m_xScrollPosition
; // As -ve as we can go
347 else if ( (m_xScrollPosition
+ nScrollInc
) > noPositions
)
348 nScrollInc
= noPositions
- m_xScrollPosition
; // As +ve as we can go
351 m_targetWindow
->Refresh();
355 if (m_yScrollPixelsPerLine
> 0)
358 m_targetWindow
->GetClientSize(&w
, &h
);
360 int nMaxHeight
= m_yScrollLines
*m_yScrollPixelsPerLine
;
361 int noPositions
= (int) ( ((nMaxHeight
- h
)/(double)m_yScrollPixelsPerLine
) + 0.5 );
365 if ( (m_yScrollPosition
+ nScrollInc
) < 0 )
366 nScrollInc
= -m_yScrollPosition
; // As -ve as we can go
367 else if ( (m_yScrollPosition
+ nScrollInc
) > noPositions
)
368 nScrollInc
= noPositions
- m_yScrollPosition
; // As +ve as we can go
371 m_targetWindow
->Refresh();
377 // Adjust the scrollbars - new version.
378 void wxScrolledWindow::AdjustScrollbars()
381 m_targetWindow
->GetClientSize(&w
, &h
);
383 int oldXScroll
= m_xScrollPosition
;
384 int oldYScroll
= m_yScrollPosition
;
386 if (m_xScrollLines
> 0)
388 // Calculate page size i.e. number of scroll units you get on the
389 // current client window
390 int noPagePositions
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 0.5 );
391 if (noPagePositions
< 1) noPagePositions
= 1;
393 // Correct position if greater than extent of canvas minus
394 // the visible portion of it or if below zero
395 m_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
396 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
398 SetScrollbar(wxHORIZONTAL
, m_xScrollPosition
, noPagePositions
, m_xScrollLines
);
399 // The amount by which we scroll when paging
400 SetScrollPageSize(wxHORIZONTAL
, noPagePositions
);
404 m_xScrollPosition
= 0;
405 SetScrollbar (wxHORIZONTAL
, 0, 0, 0, FALSE
);
408 if (m_yScrollLines
> 0)
410 // Calculate page size i.e. number of scroll units you get on the
411 // current client window
412 int noPagePositions
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 );
413 if (noPagePositions
< 1) noPagePositions
= 1;
415 // Correct position if greater than extent of canvas minus
416 // the visible portion of it or if below zero
417 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
418 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
420 SetScrollbar(wxVERTICAL
, m_yScrollPosition
, noPagePositions
, m_yScrollLines
);
421 // The amount by which we scroll when paging
422 SetScrollPageSize(wxVERTICAL
, noPagePositions
);
426 m_yScrollPosition
= 0;
427 SetScrollbar (wxVERTICAL
, 0, 0, 0, FALSE
);
430 if (oldXScroll
!= m_xScrollPosition
)
432 if (m_xScrollingEnabled
)
433 m_targetWindow
->ScrollWindow( m_xScrollPixelsPerLine
* (oldXScroll
-m_xScrollPosition
), 0, (const wxRect
*) NULL
);
435 m_targetWindow
->Refresh();
438 if (oldYScroll
!= m_yScrollPosition
)
440 if (m_yScrollingEnabled
)
441 m_targetWindow
->ScrollWindow( 0, m_yScrollPixelsPerLine
* (oldYScroll
-m_yScrollPosition
), (const wxRect
*) NULL
);
443 m_targetWindow
->Refresh();
447 // Override this function if you don't want to have wxScrolledWindow
448 // automatically change the origin according to the scroll position.
449 void wxScrolledWindow::PrepareDC(wxDC
& dc
)
451 dc
.SetDeviceOrigin( -m_xScrollPosition
* m_xScrollPixelsPerLine
,
452 -m_yScrollPosition
* m_yScrollPixelsPerLine
);
453 dc
.SetUserScale( m_scaleX
, m_scaleY
);
456 #if WXWIN_COMPATIBILITY
457 void wxScrolledWindow::GetScrollUnitsPerPage (int *x_page
, int *y_page
) const
459 *x_page
= GetScrollPageSize(wxHORIZONTAL
);
460 *y_page
= GetScrollPageSize(wxVERTICAL
);
463 void wxScrolledWindow::CalcUnscrolledPosition(int x
, int y
, float *xx
, float *yy
) const
466 *xx
= (float)(x
+ m_xScrollPosition
* m_xScrollPixelsPerLine
);
468 *yy
= (float)(y
+ m_yScrollPosition
* m_yScrollPixelsPerLine
);
470 #endif // WXWIN_COMPATIBILITY
472 void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit
, int *y_unit
) const
475 *x_unit
= m_xScrollPixelsPerLine
;
477 *y_unit
= m_yScrollPixelsPerLine
;
480 int wxScrolledWindow::GetScrollPageSize(int orient
) const
482 if ( orient
== wxHORIZONTAL
)
483 return m_xScrollLinesPerPage
;
485 return m_yScrollLinesPerPage
;
488 void wxScrolledWindow::SetScrollPageSize(int orient
, int pageSize
)
490 if ( orient
== wxHORIZONTAL
)
491 m_xScrollLinesPerPage
= pageSize
;
493 m_yScrollLinesPerPage
= pageSize
;
497 * Scroll to given position (scroll position, not pixel position)
499 void wxScrolledWindow::Scroll( int x_pos
, int y_pos
)
501 if (((x_pos
== -1) || (x_pos
== m_xScrollPosition
)) &&
502 ((y_pos
== -1) || (y_pos
== m_yScrollPosition
))) return;
505 m_targetWindow
->GetClientSize(&w
, &h
);
509 int old_x
= m_xScrollPosition
;
510 m_xScrollPosition
= x_pos
;
512 // Calculate page size i.e. number of scroll units you get on the
513 // current client window
514 int noPagePositions
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 0.5 );
515 if (noPagePositions
< 1) noPagePositions
= 1;
517 // Correct position if greater than extent of canvas minus
518 // the visible portion of it or if below zero
519 m_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
520 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
522 m_targetWindow
->SetScrollPos( wxHORIZONTAL
, m_xScrollPosition
, TRUE
);
524 m_targetWindow
->ScrollWindow( (old_x
-m_xScrollPosition
)*m_xScrollPixelsPerLine
, 0 );
528 int old_y
= m_yScrollPosition
;
529 m_yScrollPosition
= y_pos
;
531 // Calculate page size i.e. number of scroll units you get on the
532 // current client window
533 int noPagePositions
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 );
534 if (noPagePositions
< 1) noPagePositions
= 1;
536 // Correct position if greater than extent of canvas minus
537 // the visible portion of it or if below zero
538 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
539 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
541 m_targetWindow
->SetScrollPos( wxVERTICAL
, m_yScrollPosition
, TRUE
);
543 m_targetWindow
->ScrollWindow( 0, (old_y
-m_yScrollPosition
)*m_yScrollPixelsPerLine
);
548 m_targetWindow
->MacUpdateImmediately() ;
552 void wxScrolledWindow::EnableScrolling (bool x_scroll
, bool y_scroll
)
554 m_xScrollingEnabled
= x_scroll
;
555 m_yScrollingEnabled
= y_scroll
;
558 void wxScrolledWindow::GetVirtualSize (int *x
, int *y
) const
561 *x
= m_xScrollPixelsPerLine
* m_xScrollLines
;
563 *y
= m_yScrollPixelsPerLine
* m_yScrollLines
;
566 // Where the current view starts from
567 void wxScrolledWindow::GetViewStart (int *x
, int *y
) const
570 *x
= m_xScrollPosition
;
572 *y
= m_yScrollPosition
;
575 void wxScrolledWindow::CalcScrolledPosition(int x
, int y
, int *xx
, int *yy
) const
578 *xx
= x
- m_xScrollPosition
* m_xScrollPixelsPerLine
;
580 *yy
= y
- m_yScrollPosition
* m_yScrollPixelsPerLine
;
583 void wxScrolledWindow::CalcUnscrolledPosition(int x
, int y
, int *xx
, int *yy
) const
586 *xx
= x
+ m_xScrollPosition
* m_xScrollPixelsPerLine
;
588 *yy
= y
+ m_yScrollPosition
* m_yScrollPixelsPerLine
;
591 // ----------------------------------------------------------------------------
593 // ----------------------------------------------------------------------------
595 // Default OnSize resets scrollbars, if any
596 void wxScrolledWindow::OnSize(wxSizeEvent
& WXUNUSED(event
))
598 #if wxUSE_CONSTRAINTS
606 // This calls OnDraw, having adjusted the origin according to the current
608 void wxScrolledWindow::OnPaint(wxPaintEvent
& WXUNUSED(event
))
617 void wxScrolledWindow::OnKeyDown(wxKeyEvent
& event
)
619 if ( !m_xScrollPixelsPerLine
|| !m_yScrollPixelsPerLine
)
621 // stop now - no scroll line size
627 int stx
, sty
, // view origin
628 szx
, szy
, // view size (total)
629 clix
, cliy
; // view size (on screen)
631 ViewStart(&stx
, &sty
);
632 GetClientSize(&clix
, &cliy
);
633 clix
/= m_xScrollPixelsPerLine
;
634 cliy
/= m_yScrollPixelsPerLine
;
635 GetVirtualSize(&szx
, &szy
);
636 szx
/= m_xScrollPixelsPerLine
;
637 szy
/= m_yScrollPixelsPerLine
;
639 switch ( event
.KeyCode() )
643 Scroll(-1, sty
- (5 * cliy
/ 6));
648 Scroll(-1, sty
+ (5 * cliy
/ 6));
651 // notice that handling of Ctrl-Home/End is asymmetrical: Home goes to
652 // the beginning of the current line, Ctrl-Home returns to the origin
653 // while End goes to the bottom without changing horizontal position
654 // and only Ctrl-End does go to the most rightmost position as well
656 Scroll(0, event
.ControlDown() ? 0 : -1);
660 Scroll(event
.ControlDown() ? szx
- clix
: -1, szy
- cliy
);