1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxScrolledWindow implementation
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation
14 #pragma implementation "scrolwin.h"
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
21 #include "wx/dcclient.h"
27 #include "wx/generic/scrolwin.h"
29 #if !USE_SHARED_LIBRARY
30 BEGIN_EVENT_TABLE(wxScrolledWindow
, wxWindow
)
31 EVT_SCROLLWIN(wxScrolledWindow::OnScroll
)
32 EVT_SIZE(wxScrolledWindow::OnSize
)
33 EVT_PAINT(wxScrolledWindow::OnPaint
)
36 IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow
, wxWindow
)
44 // For wxRETAINED implementation
48 wxScrolledWindow::wxScrolledWindow()
50 m_xScrollPixelsPerLine
= 0;
51 m_yScrollPixelsPerLine
= 0;
52 m_xScrollingEnabled
= TRUE
;
53 m_yScrollingEnabled
= TRUE
;
54 m_xScrollPosition
= 0;
55 m_yScrollPosition
= 0;
58 m_xScrollLinesPerPage
= 0;
59 m_yScrollLinesPerPage
= 0;
64 bool wxScrolledWindow::Create(wxWindow
*parent
, wxWindowID id
,
70 m_xScrollPixelsPerLine
= 0;
71 m_yScrollPixelsPerLine
= 0;
72 m_xScrollingEnabled
= TRUE
;
73 m_yScrollingEnabled
= TRUE
;
74 m_xScrollPosition
= 0;
75 m_yScrollPosition
= 0;
78 m_xScrollLinesPerPage
= 0;
79 m_yScrollLinesPerPage
= 0;
83 return wxWindow::Create(parent
, id
, pos
, size
, style
, name
);
87 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
88 * noUnitsX/noUnitsY: : no. units per scrollbar
90 void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX
, int pixelsPerUnitY
,
91 int noUnitsX
, int noUnitsY
,
92 int xPos
, int yPos
, bool noRefresh
)
96 (noUnitsX
!= 0 && m_xScrollLines
== 0) ||
97 (noUnitsX
< m_xScrollLines
) ||
98 (noUnitsY
!= 0 && m_yScrollLines
== 0) ||
99 (noUnitsY
< m_yScrollLines
) ||
100 (xPos
!= m_xScrollPosition
) ||
101 (yPos
!= m_yScrollPosition
) ||
102 (pixelsPerUnitX
!= m_xScrollPixelsPerLine
) ||
103 (pixelsPerUnitY
!= m_yScrollPixelsPerLine
)
106 m_xScrollPixelsPerLine
= pixelsPerUnitX
;
107 m_yScrollPixelsPerLine
= pixelsPerUnitY
;
108 m_xScrollPosition
= xPos
;
109 m_yScrollPosition
= yPos
;
110 m_xScrollLines
= noUnitsX
;
111 m_yScrollLines
= noUnitsY
;
114 // Sorry, some Motif-specific code to implement a backing pixmap
115 // for the wxRETAINED style. Implementing a backing store can't
116 // be entirely generic because it relies on the wxWindowDC implementation
117 // to duplicate X drawing calls for the backing pixmap.
119 if ((m_windowStyle
& wxRETAINED
) == wxRETAINED
)
121 Display
* dpy
= XtDisplay((Widget
) GetMainWidget());
123 int totalPixelWidth
= m_xScrollLines
* m_xScrollPixelsPerLine
;
124 int totalPixelHeight
= m_yScrollLines
* m_yScrollPixelsPerLine
;
125 if (m_backingPixmap
&&
126 !((m_pixmapWidth
== totalPixelWidth
) &&
127 (m_pixmapHeight
== totalPixelHeight
)))
129 XFreePixmap (dpy
, (Pixmap
) m_backingPixmap
);
130 m_backingPixmap
= (WXPixmap
) 0;
133 if (!m_backingPixmap
&&
134 (noUnitsX
!= 0) && (noUnitsY
!= 0))
136 int depth
= wxDisplayDepth();
137 m_pixmapWidth
= totalPixelWidth
;
138 m_pixmapHeight
= totalPixelHeight
;
139 m_backingPixmap
= (WXPixmap
) XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
140 m_pixmapWidth
, m_pixmapHeight
, depth
);
148 if (do_refresh
&& !noRefresh
)
153 UpdateWindow ((HWND
) GetHWND());
157 void wxScrolledWindow::OnScroll(wxScrollWinEvent
& event
)
159 int orient
= event
.GetOrientation();
161 int nScrollInc
= CalcScrollInc(event
);
162 if (nScrollInc
== 0) return;
164 if (orient
== wxHORIZONTAL
)
166 int newPos
= m_xScrollPosition
+ nScrollInc
;
167 SetScrollPos(wxHORIZONTAL
, newPos
, TRUE
);
171 int newPos
= m_yScrollPosition
+ nScrollInc
;
172 SetScrollPos(wxVERTICAL
, newPos
, TRUE
);
175 if (orient
== wxHORIZONTAL
)
177 m_xScrollPosition
+= nScrollInc
;
181 m_yScrollPosition
+= nScrollInc
;
184 if (orient
== wxHORIZONTAL
)
186 if (m_xScrollingEnabled
)
187 ScrollWindow(-m_xScrollPixelsPerLine
* nScrollInc
, 0, (const wxRect
*) NULL
);
193 if (m_yScrollingEnabled
)
194 ScrollWindow(0, -m_yScrollPixelsPerLine
* nScrollInc
, (const wxRect
*) NULL
);
200 int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent
& event
)
202 int pos
= event
.GetPosition();
203 int orient
= event
.GetOrientation();
206 switch (event
.GetEventType())
208 case wxEVT_SCROLLWIN_TOP
:
210 if (orient
== wxHORIZONTAL
)
211 nScrollInc
= - m_xScrollPosition
;
213 nScrollInc
= - m_yScrollPosition
;
216 case wxEVT_SCROLLWIN_BOTTOM
:
218 if (orient
== wxHORIZONTAL
)
219 nScrollInc
= m_xScrollLines
- m_xScrollPosition
;
221 nScrollInc
= m_yScrollLines
- m_yScrollPosition
;
224 case wxEVT_SCROLLWIN_LINEUP
:
229 case wxEVT_SCROLLWIN_LINEDOWN
:
234 case wxEVT_SCROLLWIN_PAGEUP
:
236 if (orient
== wxHORIZONTAL
)
237 nScrollInc
= -GetScrollPageSize(wxHORIZONTAL
);
239 nScrollInc
= -GetScrollPageSize(wxVERTICAL
);
242 case wxEVT_SCROLLWIN_PAGEDOWN
:
244 if (orient
== wxHORIZONTAL
)
245 nScrollInc
= GetScrollPageSize(wxHORIZONTAL
);
247 nScrollInc
= GetScrollPageSize(wxVERTICAL
);
250 case wxEVT_SCROLLWIN_THUMBTRACK
:
252 if (orient
== wxHORIZONTAL
)
253 nScrollInc
= pos
- m_xScrollPosition
;
255 nScrollInc
= pos
- m_yScrollPosition
;
264 if (orient
== wxHORIZONTAL
)
266 if (m_xScrollPixelsPerLine
> 0) {
268 GetClientSize(&w
, &h
);
270 int nMaxWidth
= m_xScrollLines
*m_xScrollPixelsPerLine
;
271 int noPositions
= (int) ( ((nMaxWidth
- w
)/(float)m_xScrollPixelsPerLine
) + 0.5 );
275 if ( (m_xScrollPosition
+ nScrollInc
) < 0 )
276 nScrollInc
= -m_xScrollPosition
; // As -ve as we can go
277 else if ( (m_xScrollPosition
+ nScrollInc
) > noPositions
)
278 nScrollInc
= noPositions
- m_xScrollPosition
; // As +ve as we can go
285 if (m_yScrollPixelsPerLine
> 0) {
287 GetClientSize(&w
, &h
);
289 int nMaxHeight
= m_yScrollLines
*m_yScrollPixelsPerLine
;
290 int noPositions
= (int) ( ((nMaxHeight
- h
)/(float)m_yScrollPixelsPerLine
) + 0.5 );
294 if ( (m_yScrollPosition
+ nScrollInc
) < 0 )
295 nScrollInc
= -m_yScrollPosition
; // As -ve as we can go
296 else if ( (m_yScrollPosition
+ nScrollInc
) > noPositions
)
297 nScrollInc
= noPositions
- m_yScrollPosition
; // As +ve as we can go
306 // Adjust the scrollbars - new version.
307 void wxScrolledWindow::AdjustScrollbars(void)
310 GetClientSize(&w
, &h
);
312 if (m_xScrollLines
> 0)
314 // Calculate page size i.e. number of scroll units you get on the
315 // current client window
316 int noPagePositions
= (int) ( (w
/(float)m_xScrollPixelsPerLine
) + 0.5 );
317 if (noPagePositions
< 1) noPagePositions
= 1;
319 // Correct position if greater than extent of canvas minus
320 // the visible portion of it or if below zero
321 m_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
322 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
324 SetScrollbar(wxHORIZONTAL
, m_xScrollPosition
, noPagePositions
, m_xScrollLines
);
325 // The amount by which we scroll when paging
326 SetScrollPageSize(wxHORIZONTAL
, noPagePositions
);
330 m_xScrollPosition
= 0;
331 SetScrollbar (wxHORIZONTAL
, 0, 0, 0, FALSE
);
334 if (m_yScrollLines
> 0)
336 // Calculate page size i.e. number of scroll units you get on the
337 // current client window
338 int noPagePositions
= (int) ( (h
/(float)m_yScrollPixelsPerLine
) + 0.5 );
339 if (noPagePositions
< 1) noPagePositions
= 1;
341 // Correct position if greater than extent of canvas minus
342 // the visible portion of it or if below zero
343 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
344 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
346 SetScrollbar(wxVERTICAL
, m_yScrollPosition
, noPagePositions
, m_yScrollLines
);
347 // The amount by which we scroll when paging
348 SetScrollPageSize(wxVERTICAL
, noPagePositions
);
352 m_yScrollPosition
= 0;
353 SetScrollbar (wxVERTICAL
, 0, 0, 0, FALSE
);
357 // Default OnSize resets scrollbars, if any
358 void wxScrolledWindow::OnSize(wxSizeEvent
& WXUNUSED(event
))
360 #if wxUSE_CONSTRAINTS
361 if (GetAutoLayout()) Layout();
367 // This calls OnDraw, having adjusted the origin according to the current
369 void wxScrolledWindow::OnPaint(wxPaintEvent
& WXUNUSED(event
))
377 // Override this function if you don't want to have wxScrolledWindow
378 // automatically change the origin according to the scroll position.
379 void wxScrolledWindow::PrepareDC(wxDC
& dc
)
381 dc
.SetDeviceOrigin( -m_xScrollPosition
* m_xScrollPixelsPerLine
,
382 -m_yScrollPosition
* m_yScrollPixelsPerLine
);
383 dc
.SetUserScale( m_scaleX
, m_scaleY
);
386 #if WXWIN_COMPATIBILITY
387 void wxScrolledWindow::GetScrollUnitsPerPage (int *x_page
, int *y_page
) const
389 *x_page
= GetScrollPageSize(wxHORIZONTAL
);
390 *y_page
= GetScrollPageSize(wxVERTICAL
);
394 void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit
, int *y_unit
) const
396 *x_unit
= m_xScrollPixelsPerLine
;
397 *y_unit
= m_yScrollPixelsPerLine
;
400 int wxScrolledWindow::GetScrollPageSize(int orient
) const
402 if ( orient
== wxHORIZONTAL
)
403 return m_xScrollLinesPerPage
;
405 return m_yScrollLinesPerPage
;
408 void wxScrolledWindow::SetScrollPageSize(int orient
, int pageSize
)
410 if ( orient
== wxHORIZONTAL
)
411 m_xScrollLinesPerPage
= pageSize
;
413 m_yScrollLinesPerPage
= pageSize
;
417 * Scroll to given position (scroll position, not pixel position)
419 void wxScrolledWindow::Scroll( int x_pos
, int y_pos
)
421 if (((x_pos
== -1) || (x_pos
== m_xScrollPosition
)) &&
422 ((y_pos
== -1) || (y_pos
== m_yScrollPosition
))) return;
425 GetClientSize(&w
, &h
);
429 m_xScrollPosition
= x_pos
;
431 // Calculate page size i.e. number of scroll units you get on the
432 // current client window
433 int noPagePositions
= (int) ( (w
/(float)m_xScrollPixelsPerLine
) + 0.5 );
434 if (noPagePositions
< 1) noPagePositions
= 1;
436 // Correct position if greater than extent of canvas minus
437 // the visible portion of it or if below zero
438 m_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
439 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
441 SetScrollPos( wxHORIZONTAL
, m_xScrollPosition
, TRUE
);
445 m_yScrollPosition
= y_pos
;
447 // Calculate page size i.e. number of scroll units you get on the
448 // current client window
449 int noPagePositions
= (int) ( (h
/(float)m_yScrollPixelsPerLine
) + 0.5 );
450 if (noPagePositions
< 1) noPagePositions
= 1;
452 // Correct position if greater than extent of canvas minus
453 // the visible portion of it or if below zero
454 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
455 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
457 SetScrollPos( wxVERTICAL
, m_yScrollPosition
, TRUE
);
460 // BAD, BAD, can cause event loops if called from OnPaint(). KB.
465 ::UpdateWindow ((HWND
) GetHWND());
469 void wxScrolledWindow::EnableScrolling (bool x_scroll
, bool y_scroll
)
471 m_xScrollingEnabled
= x_scroll
;
472 m_yScrollingEnabled
= y_scroll
;
475 void wxScrolledWindow::GetVirtualSize (int *x
, int *y
) const
477 *x
= m_xScrollPixelsPerLine
* m_xScrollLines
;
478 *y
= m_yScrollPixelsPerLine
* m_yScrollLines
;
481 // Where the current view starts from
482 void wxScrolledWindow::ViewStart (int *x
, int *y
) const
484 *x
= m_xScrollPosition
;
485 *y
= m_yScrollPosition
;
488 void wxScrolledWindow::CalcScrolledPosition(int x
, int y
, int *xx
, int *yy
) const
490 *xx
= x
- m_xScrollPosition
* m_xScrollPixelsPerLine
;
491 *yy
= y
- m_yScrollPosition
* m_yScrollPixelsPerLine
;
494 void wxScrolledWindow::CalcUnscrolledPosition(int x
, int y
, float *xx
, float *yy
) const
496 *xx
= (float)(x
+ m_xScrollPosition
* m_xScrollPixelsPerLine
);
497 *yy
= (float)(y
+ m_yScrollPosition
* m_yScrollPixelsPerLine
);