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"
25 #define XtDisplay XTDISPLAY
28 // For compilers that support precompilation, includes "wx.h".
29 #include "wx/wxprec.h"
36 #include "wx/dcclient.h"
38 #include "wx/generic/scrolwin.h"
46 // For wxRETAINED implementation
47 #ifdef __VMS__ //VMS's Xm.h is not (yet) compatible with C++
48 //This code switches off the compiler warnings
49 # pragma message disable nosimpint
53 # pragma message enable nosimpint
57 // ----------------------------------------------------------------------------
59 // ----------------------------------------------------------------------------
61 BEGIN_EVENT_TABLE(wxScrolledWindow
, wxPanel
)
62 EVT_SCROLLWIN(wxScrolledWindow::OnScroll
)
63 EVT_SIZE(wxScrolledWindow::OnSize
)
64 EVT_PAINT(wxScrolledWindow::OnPaint
)
65 EVT_CHAR(wxScrolledWindow::OnChar
)
68 IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow
, wxPanel
)
70 // ============================================================================
72 // ============================================================================
74 // ----------------------------------------------------------------------------
75 // wxScrolledWindow creation
76 // ----------------------------------------------------------------------------
78 wxScrolledWindow::wxScrolledWindow()
80 m_xScrollPixelsPerLine
= 0;
81 m_yScrollPixelsPerLine
= 0;
82 m_xScrollingEnabled
= TRUE
;
83 m_yScrollingEnabled
= TRUE
;
84 m_xScrollPosition
= 0;
85 m_yScrollPosition
= 0;
88 m_xScrollLinesPerPage
= 0;
89 m_yScrollLinesPerPage
= 0;
92 m_targetWindow
= (wxWindow
*) NULL
;
95 bool wxScrolledWindow::Create(wxWindow
*parent
,
100 const wxString
& name
)
102 m_xScrollPixelsPerLine
= 0;
103 m_yScrollPixelsPerLine
= 0;
104 m_xScrollingEnabled
= TRUE
;
105 m_yScrollingEnabled
= TRUE
;
106 m_xScrollPosition
= 0;
107 m_yScrollPosition
= 0;
110 m_xScrollLinesPerPage
= 0;
111 m_yScrollLinesPerPage
= 0;
115 m_targetWindow
= this;
117 bool ok
= wxPanel::Create(parent
, id
, pos
, size
, style
, name
);
120 // we need to process arrows ourselves for scrolling
121 m_lDlgCode
|= DLGC_WANTARROWS
;
127 wxScrolledWindow::~wxScrolledWindow()
131 // ----------------------------------------------------------------------------
132 // setting scrolling parameters
133 // ----------------------------------------------------------------------------
136 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
137 * noUnitsX/noUnitsY: : no. units per scrollbar
139 void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX
, int pixelsPerUnitY
,
140 int noUnitsX
, int noUnitsY
,
141 int xPos
, int yPos
, bool noRefresh
)
145 CalcUnscrolledPosition(xPos
, yPos
, &xpos
, &ypos
);
148 (noUnitsX
!= 0 && m_xScrollLines
== 0) ||
149 (noUnitsX
< m_xScrollLines
&& xpos
> pixelsPerUnitX
*noUnitsX
) ||
151 (noUnitsY
!= 0 && m_yScrollLines
== 0) ||
152 (noUnitsY
< m_yScrollLines
&& ypos
> pixelsPerUnitY
*noUnitsY
) ||
153 (xPos
!= m_xScrollPosition
) ||
154 (yPos
!= m_yScrollPosition
)
155 // (pixelsPerUnitX != m_xScrollPixelsPerLine) ||
156 // (pixelsPerUnitY != m_yScrollPixelsPerLine)
159 m_xScrollPixelsPerLine
= pixelsPerUnitX
;
160 m_yScrollPixelsPerLine
= pixelsPerUnitY
;
161 m_xScrollPosition
= xPos
;
162 m_yScrollPosition
= yPos
;
163 m_xScrollLines
= noUnitsX
;
164 m_yScrollLines
= noUnitsY
;
167 // Sorry, some Motif-specific code to implement a backing pixmap
168 // for the wxRETAINED style. Implementing a backing store can't
169 // be entirely generic because it relies on the wxWindowDC implementation
170 // to duplicate X drawing calls for the backing pixmap.
172 if ((m_windowStyle
& wxRETAINED
) == wxRETAINED
)
174 Display
* dpy
= XtDisplay((Widget
) GetMainWidget());
176 int totalPixelWidth
= m_xScrollLines
* m_xScrollPixelsPerLine
;
177 int totalPixelHeight
= m_yScrollLines
* m_yScrollPixelsPerLine
;
178 if (m_backingPixmap
&&
179 !((m_pixmapWidth
== totalPixelWidth
) &&
180 (m_pixmapHeight
== totalPixelHeight
)))
182 XFreePixmap (dpy
, (Pixmap
) m_backingPixmap
);
183 m_backingPixmap
= (WXPixmap
) 0;
186 if (!m_backingPixmap
&&
187 (noUnitsX
!= 0) && (noUnitsY
!= 0))
189 int depth
= wxDisplayDepth();
190 m_pixmapWidth
= totalPixelWidth
;
191 m_pixmapHeight
= totalPixelHeight
;
192 m_backingPixmap
= (WXPixmap
) XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
193 m_pixmapWidth
, m_pixmapHeight
, depth
);
201 if (do_refresh
&& !noRefresh
)
202 m_targetWindow
->Refresh();
205 // GRG: if this turns out to be really necessary, we could
206 // at least move it to the above if { ... } so that it is
207 // only done if noRefresh = FALSE (the default). OTOH, if
208 // this doesn't break anything, which seems to be the
209 // case, we could just leave it out.
212 // UpdateWindow ((HWND) m_targetWindow->GetHWND());
215 m_targetWindow
->MacUpdateImmediately() ;
219 // ----------------------------------------------------------------------------
220 // target window handling
221 // ----------------------------------------------------------------------------
223 void wxScrolledWindow::SetTargetWindow( wxWindow
*target
)
225 wxASSERT_MSG( target
, wxT("target window must not be NULL") );
226 m_targetWindow
= target
;
229 wxWindow
*wxScrolledWindow::GetTargetWindow()
231 return m_targetWindow
;
234 // ----------------------------------------------------------------------------
235 // scrolling implementation itself
236 // ----------------------------------------------------------------------------
238 void wxScrolledWindow::OnScroll(wxScrollWinEvent
& event
)
240 int orient
= event
.GetOrientation();
242 int nScrollInc
= CalcScrollInc(event
);
243 if (nScrollInc
== 0) return;
245 if (orient
== wxHORIZONTAL
)
247 int newPos
= m_xScrollPosition
+ nScrollInc
;
248 SetScrollPos(wxHORIZONTAL
, newPos
, TRUE
);
252 int newPos
= m_yScrollPosition
+ nScrollInc
;
253 SetScrollPos(wxVERTICAL
, newPos
, TRUE
);
256 if (orient
== wxHORIZONTAL
)
258 m_xScrollPosition
+= nScrollInc
;
262 m_yScrollPosition
+= nScrollInc
;
265 if (orient
== wxHORIZONTAL
)
267 if (m_xScrollingEnabled
)
268 m_targetWindow
->ScrollWindow(-m_xScrollPixelsPerLine
* nScrollInc
, 0, (const wxRect
*) NULL
);
270 m_targetWindow
->Refresh();
274 if (m_yScrollingEnabled
)
275 m_targetWindow
->ScrollWindow(0, -m_yScrollPixelsPerLine
* nScrollInc
, (const wxRect
*) NULL
);
277 m_targetWindow
->Refresh();
280 m_targetWindow
->MacUpdateImmediately() ;
284 int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent
& event
)
286 int pos
= event
.GetPosition();
287 int orient
= event
.GetOrientation();
290 switch (event
.GetEventType())
292 case wxEVT_SCROLLWIN_TOP
:
294 if (orient
== wxHORIZONTAL
)
295 nScrollInc
= - m_xScrollPosition
;
297 nScrollInc
= - m_yScrollPosition
;
300 case wxEVT_SCROLLWIN_BOTTOM
:
302 if (orient
== wxHORIZONTAL
)
303 nScrollInc
= m_xScrollLines
- m_xScrollPosition
;
305 nScrollInc
= m_yScrollLines
- m_yScrollPosition
;
308 case wxEVT_SCROLLWIN_LINEUP
:
313 case wxEVT_SCROLLWIN_LINEDOWN
:
318 case wxEVT_SCROLLWIN_PAGEUP
:
320 if (orient
== wxHORIZONTAL
)
321 nScrollInc
= -GetScrollPageSize(wxHORIZONTAL
);
323 nScrollInc
= -GetScrollPageSize(wxVERTICAL
);
326 case wxEVT_SCROLLWIN_PAGEDOWN
:
328 if (orient
== wxHORIZONTAL
)
329 nScrollInc
= GetScrollPageSize(wxHORIZONTAL
);
331 nScrollInc
= GetScrollPageSize(wxVERTICAL
);
334 case wxEVT_SCROLLWIN_THUMBTRACK
:
335 case wxEVT_SCROLLWIN_THUMBRELEASE
:
337 if (orient
== wxHORIZONTAL
)
338 nScrollInc
= pos
- m_xScrollPosition
;
340 nScrollInc
= pos
- m_yScrollPosition
;
349 if (orient
== wxHORIZONTAL
)
351 if (m_xScrollPixelsPerLine
> 0)
354 m_targetWindow
->GetClientSize(&w
, &h
);
356 int nMaxWidth
= m_xScrollLines
*m_xScrollPixelsPerLine
;
357 int noPositions
= (int) ( ((nMaxWidth
- w
)/(double)m_xScrollPixelsPerLine
) + 0.5 );
361 if ( (m_xScrollPosition
+ nScrollInc
) < 0 )
362 nScrollInc
= -m_xScrollPosition
; // As -ve as we can go
363 else if ( (m_xScrollPosition
+ nScrollInc
) > noPositions
)
364 nScrollInc
= noPositions
- m_xScrollPosition
; // As +ve as we can go
367 m_targetWindow
->Refresh();
371 if (m_yScrollPixelsPerLine
> 0)
374 m_targetWindow
->GetClientSize(&w
, &h
);
376 int nMaxHeight
= m_yScrollLines
*m_yScrollPixelsPerLine
;
377 int noPositions
= (int) ( ((nMaxHeight
- h
)/(double)m_yScrollPixelsPerLine
) + 0.5 );
381 if ( (m_yScrollPosition
+ nScrollInc
) < 0 )
382 nScrollInc
= -m_yScrollPosition
; // As -ve as we can go
383 else if ( (m_yScrollPosition
+ nScrollInc
) > noPositions
)
384 nScrollInc
= noPositions
- m_yScrollPosition
; // As +ve as we can go
387 m_targetWindow
->Refresh();
393 // Adjust the scrollbars - new version.
394 void wxScrolledWindow::AdjustScrollbars()
397 m_targetWindow
->GetClientSize(&w
, &h
);
399 int oldXScroll
= m_xScrollPosition
;
400 int oldYScroll
= m_yScrollPosition
;
402 if (m_xScrollLines
> 0)
404 // Calculate page size i.e. number of scroll units you get on the
405 // current client window
406 int noPagePositions
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 0.5 );
407 if (noPagePositions
< 1) noPagePositions
= 1;
409 // Correct position if greater than extent of canvas minus
410 // the visible portion of it or if below zero
411 m_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
412 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
414 SetScrollbar(wxHORIZONTAL
, m_xScrollPosition
, noPagePositions
, m_xScrollLines
);
415 // The amount by which we scroll when paging
416 SetScrollPageSize(wxHORIZONTAL
, noPagePositions
);
420 m_xScrollPosition
= 0;
421 SetScrollbar (wxHORIZONTAL
, 0, 0, 0, FALSE
);
424 if (m_yScrollLines
> 0)
426 // Calculate page size i.e. number of scroll units you get on the
427 // current client window
428 int noPagePositions
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 );
429 if (noPagePositions
< 1) noPagePositions
= 1;
431 // Correct position if greater than extent of canvas minus
432 // the visible portion of it or if below zero
433 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
434 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
436 SetScrollbar(wxVERTICAL
, m_yScrollPosition
, noPagePositions
, m_yScrollLines
);
437 // The amount by which we scroll when paging
438 SetScrollPageSize(wxVERTICAL
, noPagePositions
);
442 m_yScrollPosition
= 0;
443 SetScrollbar (wxVERTICAL
, 0, 0, 0, FALSE
);
446 if (oldXScroll
!= m_xScrollPosition
)
448 if (m_xScrollingEnabled
)
449 m_targetWindow
->ScrollWindow( m_xScrollPixelsPerLine
* (oldXScroll
-m_xScrollPosition
), 0, (const wxRect
*) NULL
);
451 m_targetWindow
->Refresh();
454 if (oldYScroll
!= m_yScrollPosition
)
456 if (m_yScrollingEnabled
)
457 m_targetWindow
->ScrollWindow( 0, m_yScrollPixelsPerLine
* (oldYScroll
-m_yScrollPosition
), (const wxRect
*) NULL
);
459 m_targetWindow
->Refresh();
463 // Override this function if you don't want to have wxScrolledWindow
464 // automatically change the origin according to the scroll position.
465 void wxScrolledWindow::PrepareDC(wxDC
& dc
)
467 dc
.SetDeviceOrigin( -m_xScrollPosition
* m_xScrollPixelsPerLine
,
468 -m_yScrollPosition
* m_yScrollPixelsPerLine
);
469 dc
.SetUserScale( m_scaleX
, m_scaleY
);
472 #if WXWIN_COMPATIBILITY
473 void wxScrolledWindow::GetScrollUnitsPerPage (int *x_page
, int *y_page
) const
475 *x_page
= GetScrollPageSize(wxHORIZONTAL
);
476 *y_page
= GetScrollPageSize(wxVERTICAL
);
479 void wxScrolledWindow::CalcUnscrolledPosition(int x
, int y
, float *xx
, float *yy
) const
482 *xx
= (float)(x
+ m_xScrollPosition
* m_xScrollPixelsPerLine
);
484 *yy
= (float)(y
+ m_yScrollPosition
* m_yScrollPixelsPerLine
);
486 #endif // WXWIN_COMPATIBILITY
488 void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit
, int *y_unit
) const
491 *x_unit
= m_xScrollPixelsPerLine
;
493 *y_unit
= m_yScrollPixelsPerLine
;
496 int wxScrolledWindow::GetScrollPageSize(int orient
) const
498 if ( orient
== wxHORIZONTAL
)
499 return m_xScrollLinesPerPage
;
501 return m_yScrollLinesPerPage
;
504 void wxScrolledWindow::SetScrollPageSize(int orient
, int pageSize
)
506 if ( orient
== wxHORIZONTAL
)
507 m_xScrollLinesPerPage
= pageSize
;
509 m_yScrollLinesPerPage
= pageSize
;
513 * Scroll to given position (scroll position, not pixel position)
515 void wxScrolledWindow::Scroll( int x_pos
, int y_pos
)
520 if (((x_pos
== -1) || (x_pos
== m_xScrollPosition
)) &&
521 ((y_pos
== -1) || (y_pos
== m_yScrollPosition
))) return;
524 m_targetWindow
->GetClientSize(&w
, &h
);
526 if ((x_pos
!= -1) && (m_xScrollPixelsPerLine
))
528 int old_x
= m_xScrollPosition
;
529 m_xScrollPosition
= x_pos
;
531 // Calculate page size i.e. number of scroll units you get on the
532 // current client window
533 int noPagePositions
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 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_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
539 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
541 if (old_x
!= m_xScrollPosition
) {
542 m_targetWindow
->SetScrollPos( wxHORIZONTAL
, m_xScrollPosition
, TRUE
);
543 m_targetWindow
->ScrollWindow( (old_x
-m_xScrollPosition
)*m_xScrollPixelsPerLine
, 0 );
546 if ((y_pos
!= -1) && (m_yScrollPixelsPerLine
))
548 int old_y
= m_yScrollPosition
;
549 m_yScrollPosition
= y_pos
;
551 // Calculate page size i.e. number of scroll units you get on the
552 // current client window
553 int noPagePositions
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 );
554 if (noPagePositions
< 1) noPagePositions
= 1;
556 // Correct position if greater than extent of canvas minus
557 // the visible portion of it or if below zero
558 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
559 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
561 if (old_y
!= m_yScrollPosition
) {
562 m_targetWindow
->SetScrollPos( wxVERTICAL
, m_yScrollPosition
, TRUE
);
563 m_targetWindow
->ScrollWindow( 0, (old_y
-m_yScrollPosition
)*m_yScrollPixelsPerLine
);
568 m_targetWindow
->MacUpdateImmediately();
572 void wxScrolledWindow::EnableScrolling (bool x_scroll
, bool y_scroll
)
574 m_xScrollingEnabled
= x_scroll
;
575 m_yScrollingEnabled
= y_scroll
;
578 void wxScrolledWindow::GetVirtualSize (int *x
, int *y
) const
581 *x
= m_xScrollPixelsPerLine
* m_xScrollLines
;
583 *y
= m_yScrollPixelsPerLine
* m_yScrollLines
;
586 // Where the current view starts from
587 void wxScrolledWindow::GetViewStart (int *x
, int *y
) const
590 *x
= m_xScrollPosition
;
592 *y
= m_yScrollPosition
;
595 void wxScrolledWindow::CalcScrolledPosition(int x
, int y
, int *xx
, int *yy
) const
598 *xx
= x
- m_xScrollPosition
* m_xScrollPixelsPerLine
;
600 *yy
= y
- m_yScrollPosition
* m_yScrollPixelsPerLine
;
603 void wxScrolledWindow::CalcUnscrolledPosition(int x
, int y
, int *xx
, int *yy
) const
606 *xx
= x
+ m_xScrollPosition
* m_xScrollPixelsPerLine
;
608 *yy
= y
+ m_yScrollPosition
* m_yScrollPixelsPerLine
;
611 // ----------------------------------------------------------------------------
613 // ----------------------------------------------------------------------------
615 // Default OnSize resets scrollbars, if any
616 void wxScrolledWindow::OnSize(wxSizeEvent
& WXUNUSED(event
))
618 #if wxUSE_CONSTRAINTS
626 // This calls OnDraw, having adjusted the origin according to the current
628 void wxScrolledWindow::OnPaint(wxPaintEvent
& WXUNUSED(event
))
636 // kbd handling: notice that we use OnChar() and not OnKeyDown() for
637 // compatibility here - if we used OnKeyDown(), the programs which process
638 // arrows themselves in their OnChar() would never get the message and like
639 // this they always have the priority
640 void wxScrolledWindow::OnChar(wxKeyEvent
& event
)
642 int stx
, sty
, // view origin
643 szx
, szy
, // view size (total)
644 clix
, cliy
; // view size (on screen)
646 ViewStart(&stx
, &sty
);
647 GetClientSize(&clix
, &cliy
);
648 GetVirtualSize(&szx
, &szy
);
650 if( m_xScrollPixelsPerLine
)
652 clix
/= m_xScrollPixelsPerLine
;
653 szx
/= m_xScrollPixelsPerLine
;
660 if( m_yScrollPixelsPerLine
)
662 cliy
/= m_yScrollPixelsPerLine
;
663 szy
/= m_yScrollPixelsPerLine
;
672 switch ( event
.KeyCode() )
676 dsty
= sty
- (5 * cliy
/ 6);
677 Scroll(-1, (dsty
== -1) ? 0 : dsty
);
682 Scroll(-1, sty
+ (5 * cliy
/ 6));
686 Scroll(0, event
.ControlDown() ? 0 : -1);
690 Scroll(szx
- clix
, event
.ControlDown() ? szy
- cliy
: -1);