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"
30 BEGIN_EVENT_TABLE(wxScrolledWindow
, wxPanel
)
31 EVT_SCROLLWIN(wxScrolledWindow::OnScroll
)
32 EVT_SIZE(wxScrolledWindow::OnSize
)
33 EVT_PAINT(wxScrolledWindow::OnPaint
)
36 IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow
, wxPanel
)
43 // For wxRETAINED implementation
44 #ifdef __VMS__ //VMS's Xm.h is not (yet) compatible with C++
45 //This code switches off the compiler warnings
46 # pragma message disable nosimpint
50 # pragma message enable nosimpint
54 wxScrolledWindow::wxScrolledWindow()
56 m_xScrollPixelsPerLine
= 0;
57 m_yScrollPixelsPerLine
= 0;
58 m_xScrollingEnabled
= TRUE
;
59 m_yScrollingEnabled
= TRUE
;
60 m_xScrollPosition
= 0;
61 m_yScrollPosition
= 0;
64 m_xScrollLinesPerPage
= 0;
65 m_yScrollLinesPerPage
= 0;
70 bool wxScrolledWindow::Create(wxWindow
*parent
, wxWindowID id
,
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;
89 m_targetWindow
= this;
91 return wxPanel::Create(parent
, id
, pos
, size
, style
, name
);
95 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
96 * noUnitsX/noUnitsY: : no. units per scrollbar
98 void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX
, int pixelsPerUnitY
,
99 int noUnitsX
, int noUnitsY
,
100 int xPos
, int yPos
, bool noRefresh
)
104 (noUnitsX
!= 0 && m_xScrollLines
== 0) ||
105 (noUnitsX
< m_xScrollLines
) ||
106 (noUnitsY
!= 0 && m_yScrollLines
== 0) ||
107 (noUnitsY
< m_yScrollLines
) ||
108 (xPos
!= m_xScrollPosition
) ||
109 (yPos
!= m_yScrollPosition
) ||
110 (pixelsPerUnitX
!= m_xScrollPixelsPerLine
) ||
111 (pixelsPerUnitY
!= m_yScrollPixelsPerLine
)
114 m_xScrollPixelsPerLine
= pixelsPerUnitX
;
115 m_yScrollPixelsPerLine
= pixelsPerUnitY
;
116 m_xScrollPosition
= xPos
;
117 m_yScrollPosition
= yPos
;
118 m_xScrollLines
= noUnitsX
;
119 m_yScrollLines
= noUnitsY
;
122 // Sorry, some Motif-specific code to implement a backing pixmap
123 // for the wxRETAINED style. Implementing a backing store can't
124 // be entirely generic because it relies on the wxWindowDC implementation
125 // to duplicate X drawing calls for the backing pixmap.
127 if ((m_windowStyle
& wxRETAINED
) == wxRETAINED
)
129 Display
* dpy
= XtDisplay((Widget
) GetMainWidget());
131 int totalPixelWidth
= m_xScrollLines
* m_xScrollPixelsPerLine
;
132 int totalPixelHeight
= m_yScrollLines
* m_yScrollPixelsPerLine
;
133 if (m_backingPixmap
&&
134 !((m_pixmapWidth
== totalPixelWidth
) &&
135 (m_pixmapHeight
== totalPixelHeight
)))
137 XFreePixmap (dpy
, (Pixmap
) m_backingPixmap
);
138 m_backingPixmap
= (WXPixmap
) 0;
141 if (!m_backingPixmap
&&
142 (noUnitsX
!= 0) && (noUnitsY
!= 0))
144 int depth
= wxDisplayDepth();
145 m_pixmapWidth
= totalPixelWidth
;
146 m_pixmapHeight
= totalPixelHeight
;
147 m_backingPixmap
= (WXPixmap
) XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
148 m_pixmapWidth
, m_pixmapHeight
, depth
);
156 if (do_refresh
&& !noRefresh
)
157 m_targetWindow
->Refresh();
160 // GRG: if this turns out to be really necessary, we could
161 // at least move it to the above if { ... } so that it is
162 // only done if noRefresh = FALSE (the default). OTOH, if
163 // this doesn't break anything, which seems to be the
164 // case, we could just leave it out.
167 // UpdateWindow ((HWND) m_targetWindow->GetHWND());
170 m_targetWindow
->MacUpdateImmediately() ;
174 wxScrolledWindow::~wxScrolledWindow()
178 void wxScrolledWindow::SetTargetWindow( wxWindow
*target
)
180 wxASSERT_MSG( target
, wxT("target window must not be NULL") );
181 m_targetWindow
= target
;
184 wxWindow
*wxScrolledWindow::GetTargetWindow()
186 return m_targetWindow
;
189 void wxScrolledWindow::OnScroll(wxScrollWinEvent
& event
)
191 int orient
= event
.GetOrientation();
193 int nScrollInc
= CalcScrollInc(event
);
194 if (nScrollInc
== 0) return;
196 if (orient
== wxHORIZONTAL
)
198 int newPos
= m_xScrollPosition
+ nScrollInc
;
199 SetScrollPos(wxHORIZONTAL
, newPos
, TRUE
);
203 int newPos
= m_yScrollPosition
+ nScrollInc
;
204 SetScrollPos(wxVERTICAL
, newPos
, TRUE
);
207 if (orient
== wxHORIZONTAL
)
209 m_xScrollPosition
+= nScrollInc
;
213 m_yScrollPosition
+= nScrollInc
;
216 if (orient
== wxHORIZONTAL
)
218 if (m_xScrollingEnabled
)
219 m_targetWindow
->ScrollWindow(-m_xScrollPixelsPerLine
* nScrollInc
, 0, (const wxRect
*) NULL
);
221 m_targetWindow
->Refresh();
225 if (m_yScrollingEnabled
)
226 m_targetWindow
->ScrollWindow(0, -m_yScrollPixelsPerLine
* nScrollInc
, (const wxRect
*) NULL
);
228 m_targetWindow
->Refresh();
231 m_targetWindow
->MacUpdateImmediately() ;
235 int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent
& event
)
237 int pos
= event
.GetPosition();
238 int orient
= event
.GetOrientation();
241 switch (event
.GetEventType())
243 case wxEVT_SCROLLWIN_TOP
:
245 if (orient
== wxHORIZONTAL
)
246 nScrollInc
= - m_xScrollPosition
;
248 nScrollInc
= - m_yScrollPosition
;
251 case wxEVT_SCROLLWIN_BOTTOM
:
253 if (orient
== wxHORIZONTAL
)
254 nScrollInc
= m_xScrollLines
- m_xScrollPosition
;
256 nScrollInc
= m_yScrollLines
- m_yScrollPosition
;
259 case wxEVT_SCROLLWIN_LINEUP
:
264 case wxEVT_SCROLLWIN_LINEDOWN
:
269 case wxEVT_SCROLLWIN_PAGEUP
:
271 if (orient
== wxHORIZONTAL
)
272 nScrollInc
= -GetScrollPageSize(wxHORIZONTAL
);
274 nScrollInc
= -GetScrollPageSize(wxVERTICAL
);
277 case wxEVT_SCROLLWIN_PAGEDOWN
:
279 if (orient
== wxHORIZONTAL
)
280 nScrollInc
= GetScrollPageSize(wxHORIZONTAL
);
282 nScrollInc
= GetScrollPageSize(wxVERTICAL
);
285 case wxEVT_SCROLLWIN_THUMBTRACK
:
287 if (orient
== wxHORIZONTAL
)
288 nScrollInc
= pos
- m_xScrollPosition
;
290 nScrollInc
= pos
- m_yScrollPosition
;
299 if (orient
== wxHORIZONTAL
)
301 if (m_xScrollPixelsPerLine
> 0)
304 m_targetWindow
->GetClientSize(&w
, &h
);
306 int nMaxWidth
= m_xScrollLines
*m_xScrollPixelsPerLine
;
307 int noPositions
= (int) ( ((nMaxWidth
- w
)/(double)m_xScrollPixelsPerLine
) + 0.5 );
311 if ( (m_xScrollPosition
+ nScrollInc
) < 0 )
312 nScrollInc
= -m_xScrollPosition
; // As -ve as we can go
313 else if ( (m_xScrollPosition
+ nScrollInc
) > noPositions
)
314 nScrollInc
= noPositions
- m_xScrollPosition
; // As +ve as we can go
317 m_targetWindow
->Refresh();
321 if (m_yScrollPixelsPerLine
> 0)
324 m_targetWindow
->GetClientSize(&w
, &h
);
326 int nMaxHeight
= m_yScrollLines
*m_yScrollPixelsPerLine
;
327 int noPositions
= (int) ( ((nMaxHeight
- h
)/(double)m_yScrollPixelsPerLine
) + 0.5 );
331 if ( (m_yScrollPosition
+ nScrollInc
) < 0 )
332 nScrollInc
= -m_yScrollPosition
; // As -ve as we can go
333 else if ( (m_yScrollPosition
+ nScrollInc
) > noPositions
)
334 nScrollInc
= noPositions
- m_yScrollPosition
; // As +ve as we can go
337 m_targetWindow
->Refresh();
343 // Adjust the scrollbars - new version.
344 void wxScrolledWindow::AdjustScrollbars()
347 m_targetWindow
->GetClientSize(&w
, &h
);
349 int oldXScroll
= m_xScrollPosition
;
350 int oldYScroll
= m_yScrollPosition
;
352 if (m_xScrollLines
> 0)
354 // Calculate page size i.e. number of scroll units you get on the
355 // current client window
356 int noPagePositions
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 0.5 );
357 if (noPagePositions
< 1) noPagePositions
= 1;
359 // Correct position if greater than extent of canvas minus
360 // the visible portion of it or if below zero
361 m_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
362 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
364 SetScrollbar(wxHORIZONTAL
, m_xScrollPosition
, noPagePositions
, m_xScrollLines
);
365 // The amount by which we scroll when paging
366 SetScrollPageSize(wxHORIZONTAL
, noPagePositions
);
370 m_xScrollPosition
= 0;
371 SetScrollbar (wxHORIZONTAL
, 0, 0, 0, FALSE
);
374 if (m_yScrollLines
> 0)
376 // Calculate page size i.e. number of scroll units you get on the
377 // current client window
378 int noPagePositions
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 );
379 if (noPagePositions
< 1) noPagePositions
= 1;
381 // Correct position if greater than extent of canvas minus
382 // the visible portion of it or if below zero
383 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
384 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
386 SetScrollbar(wxVERTICAL
, m_yScrollPosition
, noPagePositions
, m_yScrollLines
);
387 // The amount by which we scroll when paging
388 SetScrollPageSize(wxVERTICAL
, noPagePositions
);
392 m_yScrollPosition
= 0;
393 SetScrollbar (wxVERTICAL
, 0, 0, 0, FALSE
);
396 if (oldXScroll
!= m_xScrollPosition
)
398 if (m_xScrollingEnabled
)
399 m_targetWindow
->ScrollWindow( m_xScrollPixelsPerLine
* (oldXScroll
-m_xScrollPosition
), 0, (const wxRect
*) NULL
);
401 m_targetWindow
->Refresh();
404 if (oldYScroll
!= m_yScrollPosition
)
406 if (m_yScrollingEnabled
)
407 m_targetWindow
->ScrollWindow( 0, m_yScrollPixelsPerLine
* (oldYScroll
-m_yScrollPosition
), (const wxRect
*) NULL
);
409 m_targetWindow
->Refresh();
413 // Default OnSize resets scrollbars, if any
414 void wxScrolledWindow::OnSize(wxSizeEvent
& WXUNUSED(event
))
416 #if wxUSE_CONSTRAINTS
417 if (GetAutoLayout()) Layout();
423 // This calls OnDraw, having adjusted the origin according to the current
425 void wxScrolledWindow::OnPaint(wxPaintEvent
& WXUNUSED(event
))
433 // Override this function if you don't want to have wxScrolledWindow
434 // automatically change the origin according to the scroll position.
435 void wxScrolledWindow::PrepareDC(wxDC
& dc
)
437 dc
.SetDeviceOrigin( -m_xScrollPosition
* m_xScrollPixelsPerLine
,
438 -m_yScrollPosition
* m_yScrollPixelsPerLine
);
439 dc
.SetUserScale( m_scaleX
, m_scaleY
);
442 #if WXWIN_COMPATIBILITY
443 void wxScrolledWindow::GetScrollUnitsPerPage (int *x_page
, int *y_page
) const
445 *x_page
= GetScrollPageSize(wxHORIZONTAL
);
446 *y_page
= GetScrollPageSize(wxVERTICAL
);
449 void wxScrolledWindow::CalcUnscrolledPosition(int x
, int y
, float *xx
, float *yy
) const
452 *xx
= (float)(x
+ m_xScrollPosition
* m_xScrollPixelsPerLine
);
454 *yy
= (float)(y
+ m_yScrollPosition
* m_yScrollPixelsPerLine
);
456 #endif // WXWIN_COMPATIBILITY
458 void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit
, int *y_unit
) const
461 *x_unit
= m_xScrollPixelsPerLine
;
463 *y_unit
= m_yScrollPixelsPerLine
;
466 int wxScrolledWindow::GetScrollPageSize(int orient
) const
468 if ( orient
== wxHORIZONTAL
)
469 return m_xScrollLinesPerPage
;
471 return m_yScrollLinesPerPage
;
474 void wxScrolledWindow::SetScrollPageSize(int orient
, int pageSize
)
476 if ( orient
== wxHORIZONTAL
)
477 m_xScrollLinesPerPage
= pageSize
;
479 m_yScrollLinesPerPage
= pageSize
;
483 * Scroll to given position (scroll position, not pixel position)
485 void wxScrolledWindow::Scroll( int x_pos
, int y_pos
)
487 if (((x_pos
== -1) || (x_pos
== m_xScrollPosition
)) &&
488 ((y_pos
== -1) || (y_pos
== m_yScrollPosition
))) return;
491 m_targetWindow
->GetClientSize(&w
, &h
);
495 int old_x
= m_xScrollPosition
;
496 m_xScrollPosition
= x_pos
;
498 // Calculate page size i.e. number of scroll units you get on the
499 // current client window
500 int noPagePositions
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 0.5 );
501 if (noPagePositions
< 1) noPagePositions
= 1;
503 // Correct position if greater than extent of canvas minus
504 // the visible portion of it or if below zero
505 m_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
506 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
508 m_targetWindow
->SetScrollPos( wxHORIZONTAL
, m_xScrollPosition
, TRUE
);
510 m_targetWindow
->ScrollWindow( (old_x
-m_xScrollPosition
)*m_xScrollPixelsPerLine
, 0 );
514 int old_y
= m_yScrollPosition
;
515 m_yScrollPosition
= y_pos
;
517 // Calculate page size i.e. number of scroll units you get on the
518 // current client window
519 int noPagePositions
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 );
520 if (noPagePositions
< 1) noPagePositions
= 1;
522 // Correct position if greater than extent of canvas minus
523 // the visible portion of it or if below zero
524 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
525 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
527 m_targetWindow
->SetScrollPos( wxVERTICAL
, m_yScrollPosition
, TRUE
);
529 m_targetWindow
->ScrollWindow( 0, (old_y
-m_yScrollPosition
)*m_yScrollPixelsPerLine
);
534 m_targetWindow
->MacUpdateImmediately() ;
538 void wxScrolledWindow::EnableScrolling (bool x_scroll
, bool y_scroll
)
540 m_xScrollingEnabled
= x_scroll
;
541 m_yScrollingEnabled
= y_scroll
;
544 void wxScrolledWindow::GetVirtualSize (int *x
, int *y
) const
547 *x
= m_xScrollPixelsPerLine
* m_xScrollLines
;
549 *y
= m_yScrollPixelsPerLine
* m_yScrollLines
;
552 // Where the current view starts from
553 void wxScrolledWindow::GetViewStart (int *x
, int *y
) const
556 *x
= m_xScrollPosition
;
558 *y
= m_yScrollPosition
;
561 void wxScrolledWindow::CalcScrolledPosition(int x
, int y
, int *xx
, int *yy
) const
564 *xx
= x
- m_xScrollPosition
* m_xScrollPixelsPerLine
;
566 *yy
= y
- m_yScrollPosition
* m_yScrollPixelsPerLine
;
569 void wxScrolledWindow::CalcUnscrolledPosition(int x
, int y
, int *xx
, int *yy
) const
572 *xx
= x
+ m_xScrollPosition
* m_xScrollPixelsPerLine
;
574 *yy
= y
+ m_yScrollPosition
* m_yScrollPixelsPerLine
;