1 /////////////////////////////////////////////////////////////////////////////
2 // Name: generic/scrolwin.cpp
3 // Purpose: wxGenericScrolledWindow 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
58 #include "wx/scrolwin.h"
59 IMPLEMENT_CLASS(wxScrolledWindow
, wxGenericScrolledWindow
)
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 BEGIN_EVENT_TABLE(wxGenericScrolledWindow
, wxPanel
)
67 EVT_SCROLLWIN(wxGenericScrolledWindow::OnScroll
)
68 EVT_SIZE(wxGenericScrolledWindow::OnSize
)
69 EVT_PAINT(wxGenericScrolledWindow::OnPaint
)
70 EVT_CHAR(wxGenericScrolledWindow::OnChar
)
71 EVT_MOUSEWHEEL(wxGenericScrolledWindow::OnMouseWheel
)
74 IMPLEMENT_DYNAMIC_CLASS(wxGenericScrolledWindow
, wxPanel
)
76 // ============================================================================
78 // ============================================================================
80 // ----------------------------------------------------------------------------
81 // wxGenericScrolledWindow creation
82 // ----------------------------------------------------------------------------
84 wxGenericScrolledWindow::wxGenericScrolledWindow()
86 m_xScrollPixelsPerLine
= 0;
87 m_yScrollPixelsPerLine
= 0;
88 m_xScrollingEnabled
= TRUE
;
89 m_yScrollingEnabled
= TRUE
;
90 m_xScrollPosition
= 0;
91 m_yScrollPosition
= 0;
94 m_xScrollLinesPerPage
= 0;
95 m_yScrollLinesPerPage
= 0;
99 m_targetWindow
= (wxWindow
*) NULL
;
102 bool wxGenericScrolledWindow::Create(wxWindow
*parent
,
107 const wxString
& name
)
109 m_xScrollPixelsPerLine
= 0;
110 m_yScrollPixelsPerLine
= 0;
111 m_xScrollingEnabled
= TRUE
;
112 m_yScrollingEnabled
= TRUE
;
113 m_xScrollPosition
= 0;
114 m_yScrollPosition
= 0;
117 m_xScrollLinesPerPage
= 0;
118 m_yScrollLinesPerPage
= 0;
123 m_targetWindow
= this;
125 bool ok
= wxPanel::Create(parent
, id
, pos
, size
, style
, name
);
128 // we need to process arrows ourselves for scrolling
129 m_lDlgCode
|= DLGC_WANTARROWS
;
135 wxGenericScrolledWindow::~wxGenericScrolledWindow()
139 // ----------------------------------------------------------------------------
140 // setting scrolling parameters
141 // ----------------------------------------------------------------------------
144 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
145 * noUnitsX/noUnitsY: : no. units per scrollbar
147 void wxGenericScrolledWindow::SetScrollbars (int pixelsPerUnitX
, int pixelsPerUnitY
,
148 int noUnitsX
, int noUnitsY
,
149 int xPos
, int yPos
, bool noRefresh
)
153 CalcUnscrolledPosition(xPos
, yPos
, &xpos
, &ypos
);
156 (noUnitsX
!= 0 && m_xScrollLines
== 0) ||
157 (noUnitsX
< m_xScrollLines
&& xpos
> pixelsPerUnitX
*noUnitsX
) ||
159 (noUnitsY
!= 0 && m_yScrollLines
== 0) ||
160 (noUnitsY
< m_yScrollLines
&& ypos
> pixelsPerUnitY
*noUnitsY
) ||
161 (xPos
!= m_xScrollPosition
) ||
162 (yPos
!= m_yScrollPosition
)
163 // (pixelsPerUnitX != m_xScrollPixelsPerLine) ||
164 // (pixelsPerUnitY != m_yScrollPixelsPerLine)
167 m_xScrollPixelsPerLine
= pixelsPerUnitX
;
168 m_yScrollPixelsPerLine
= pixelsPerUnitY
;
169 m_xScrollPosition
= xPos
;
170 m_yScrollPosition
= yPos
;
171 m_xScrollLines
= noUnitsX
;
172 m_yScrollLines
= noUnitsY
;
175 // Sorry, some Motif-specific code to implement a backing pixmap
176 // for the wxRETAINED style. Implementing a backing store can't
177 // be entirely generic because it relies on the wxWindowDC implementation
178 // to duplicate X drawing calls for the backing pixmap.
180 if ((m_windowStyle
& wxRETAINED
) == wxRETAINED
)
182 Display
* dpy
= XtDisplay((Widget
) GetMainWidget());
184 int totalPixelWidth
= m_xScrollLines
* m_xScrollPixelsPerLine
;
185 int totalPixelHeight
= m_yScrollLines
* m_yScrollPixelsPerLine
;
186 if (m_backingPixmap
&&
187 !((m_pixmapWidth
== totalPixelWidth
) &&
188 (m_pixmapHeight
== totalPixelHeight
)))
190 XFreePixmap (dpy
, (Pixmap
) m_backingPixmap
);
191 m_backingPixmap
= (WXPixmap
) 0;
194 if (!m_backingPixmap
&&
195 (noUnitsX
!= 0) && (noUnitsY
!= 0))
197 int depth
= wxDisplayDepth();
198 m_pixmapWidth
= totalPixelWidth
;
199 m_pixmapHeight
= totalPixelHeight
;
200 m_backingPixmap
= (WXPixmap
) XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
201 m_pixmapWidth
, m_pixmapHeight
, depth
);
209 if (do_refresh
&& !noRefresh
)
210 m_targetWindow
->Refresh();
213 // GRG: if this turns out to be really necessary, we could
214 // at least move it to the above if { ... } so that it is
215 // only done if noRefresh = FALSE (the default). OTOH, if
216 // this doesn't break anything, which seems to be the
217 // case, we could just leave it out.
220 // UpdateWindow ((HWND) m_targetWindow->GetHWND());
223 m_targetWindow
->MacUpdateImmediately() ;
227 // ----------------------------------------------------------------------------
228 // target window handling
229 // ----------------------------------------------------------------------------
231 void wxGenericScrolledWindow::SetTargetWindow( wxWindow
*target
)
233 wxASSERT_MSG( target
, wxT("target window must not be NULL") );
234 m_targetWindow
= target
;
237 wxWindow
*wxGenericScrolledWindow::GetTargetWindow()
239 return m_targetWindow
;
242 // ----------------------------------------------------------------------------
243 // scrolling implementation itself
244 // ----------------------------------------------------------------------------
246 void wxGenericScrolledWindow::OnScroll(wxScrollWinEvent
& event
)
248 int orient
= event
.GetOrientation();
250 int nScrollInc
= CalcScrollInc(event
);
251 if (nScrollInc
== 0) return;
253 if (orient
== wxHORIZONTAL
)
255 int newPos
= m_xScrollPosition
+ nScrollInc
;
256 SetScrollPos(wxHORIZONTAL
, newPos
, TRUE
);
260 int newPos
= m_yScrollPosition
+ nScrollInc
;
261 SetScrollPos(wxVERTICAL
, newPos
, TRUE
);
264 if (orient
== wxHORIZONTAL
)
266 m_xScrollPosition
+= nScrollInc
;
270 m_yScrollPosition
+= nScrollInc
;
273 if (orient
== wxHORIZONTAL
)
275 if (m_xScrollingEnabled
)
276 m_targetWindow
->ScrollWindow(-m_xScrollPixelsPerLine
* nScrollInc
, 0, (const wxRect
*) NULL
);
278 m_targetWindow
->Refresh();
282 if (m_yScrollingEnabled
)
283 m_targetWindow
->ScrollWindow(0, -m_yScrollPixelsPerLine
* nScrollInc
, (const wxRect
*) NULL
);
285 m_targetWindow
->Refresh();
288 m_targetWindow
->MacUpdateImmediately() ;
292 int wxGenericScrolledWindow::CalcScrollInc(wxScrollWinEvent
& event
)
294 int pos
= event
.GetPosition();
295 int orient
= event
.GetOrientation();
298 if (event
.GetEventType() == wxEVT_SCROLLWIN_TOP
)
300 if (orient
== wxHORIZONTAL
)
301 nScrollInc
= - m_xScrollPosition
;
303 nScrollInc
= - m_yScrollPosition
;
305 if (event
.GetEventType() == wxEVT_SCROLLWIN_BOTTOM
)
307 if (orient
== wxHORIZONTAL
)
308 nScrollInc
= m_xScrollLines
- m_xScrollPosition
;
310 nScrollInc
= m_yScrollLines
- m_yScrollPosition
;
312 if (event
.GetEventType() == wxEVT_SCROLLWIN_LINEUP
)
316 if (event
.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN
)
320 if (event
.GetEventType() == wxEVT_SCROLLWIN_PAGEUP
)
322 if (orient
== wxHORIZONTAL
)
323 nScrollInc
= -GetScrollPageSize(wxHORIZONTAL
);
325 nScrollInc
= -GetScrollPageSize(wxVERTICAL
);
327 if (event
.GetEventType() == wxEVT_SCROLLWIN_PAGEDOWN
)
329 if (orient
== wxHORIZONTAL
)
330 nScrollInc
= GetScrollPageSize(wxHORIZONTAL
);
332 nScrollInc
= GetScrollPageSize(wxVERTICAL
);
334 if ((event
.GetEventType() == wxEVT_SCROLLWIN_THUMBTRACK
) ||
335 (event
.GetEventType() == wxEVT_SCROLLWIN_THUMBRELEASE
))
337 if (orient
== wxHORIZONTAL
)
338 nScrollInc
= pos
- m_xScrollPosition
;
340 nScrollInc
= pos
- m_yScrollPosition
;
343 if (orient
== wxHORIZONTAL
)
345 if (m_xScrollPixelsPerLine
> 0)
348 m_targetWindow
->GetClientSize(&w
, &h
);
350 int nMaxWidth
= m_xScrollLines
*m_xScrollPixelsPerLine
;
351 int noPositions
= (int) ( ((nMaxWidth
- w
)/(double)m_xScrollPixelsPerLine
) + 0.5 );
355 if ( (m_xScrollPosition
+ nScrollInc
) < 0 )
356 nScrollInc
= -m_xScrollPosition
; // As -ve as we can go
357 else if ( (m_xScrollPosition
+ nScrollInc
) > noPositions
)
358 nScrollInc
= noPositions
- m_xScrollPosition
; // As +ve as we can go
361 m_targetWindow
->Refresh();
365 if (m_yScrollPixelsPerLine
> 0)
368 m_targetWindow
->GetClientSize(&w
, &h
);
370 int nMaxHeight
= m_yScrollLines
*m_yScrollPixelsPerLine
;
371 int noPositions
= (int) ( ((nMaxHeight
- h
)/(double)m_yScrollPixelsPerLine
) + 0.5 );
375 if ( (m_yScrollPosition
+ nScrollInc
) < 0 )
376 nScrollInc
= -m_yScrollPosition
; // As -ve as we can go
377 else if ( (m_yScrollPosition
+ nScrollInc
) > noPositions
)
378 nScrollInc
= noPositions
- m_yScrollPosition
; // As +ve as we can go
381 m_targetWindow
->Refresh();
387 // Adjust the scrollbars - new version.
388 void wxGenericScrolledWindow::AdjustScrollbars()
391 m_targetWindow
->MacUpdateImmediately();
395 m_targetWindow
->GetClientSize(&w
, &h
);
397 int oldXScroll
= m_xScrollPosition
;
398 int oldYScroll
= m_yScrollPosition
;
400 if (m_xScrollLines
> 0)
402 // Calculate page size i.e. number of scroll units you get on the
403 // current client window
404 int noPagePositions
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 0.5 );
405 if (noPagePositions
< 1) noPagePositions
= 1;
407 // Correct position if greater than extent of canvas minus
408 // the visible portion of it or if below zero
409 m_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
410 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
412 SetScrollbar(wxHORIZONTAL
, m_xScrollPosition
, noPagePositions
, m_xScrollLines
);
413 // The amount by which we scroll when paging
414 SetScrollPageSize(wxHORIZONTAL
, noPagePositions
);
418 m_xScrollPosition
= 0;
419 SetScrollbar (wxHORIZONTAL
, 0, 0, 0, FALSE
);
422 if (m_yScrollLines
> 0)
424 // Calculate page size i.e. number of scroll units you get on the
425 // current client window
426 int noPagePositions
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 );
427 if (noPagePositions
< 1) noPagePositions
= 1;
429 // Correct position if greater than extent of canvas minus
430 // the visible portion of it or if below zero
431 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
432 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
434 SetScrollbar(wxVERTICAL
, m_yScrollPosition
, noPagePositions
, m_yScrollLines
);
435 // The amount by which we scroll when paging
436 SetScrollPageSize(wxVERTICAL
, noPagePositions
);
440 m_yScrollPosition
= 0;
441 SetScrollbar (wxVERTICAL
, 0, 0, 0, FALSE
);
444 if (oldXScroll
!= m_xScrollPosition
)
446 if (m_xScrollingEnabled
)
447 m_targetWindow
->ScrollWindow( m_xScrollPixelsPerLine
* (oldXScroll
-m_xScrollPosition
), 0, (const wxRect
*) NULL
);
449 m_targetWindow
->Refresh();
452 if (oldYScroll
!= m_yScrollPosition
)
454 if (m_yScrollingEnabled
)
455 m_targetWindow
->ScrollWindow( 0, m_yScrollPixelsPerLine
* (oldYScroll
-m_yScrollPosition
), (const wxRect
*) NULL
);
457 m_targetWindow
->Refresh();
461 m_targetWindow
->MacUpdateImmediately();
465 // Override this function if you don't want to have wxGenericScrolledWindow
466 // automatically change the origin according to the scroll position.
467 void wxGenericScrolledWindow::PrepareDC(wxDC
& dc
)
469 dc
.SetDeviceOrigin( -m_xScrollPosition
* m_xScrollPixelsPerLine
,
470 -m_yScrollPosition
* m_yScrollPixelsPerLine
);
471 dc
.SetUserScale( m_scaleX
, m_scaleY
);
474 #if WXWIN_COMPATIBILITY
475 void wxGenericScrolledWindow::GetScrollUnitsPerPage (int *x_page
, int *y_page
) const
477 *x_page
= GetScrollPageSize(wxHORIZONTAL
);
478 *y_page
= GetScrollPageSize(wxVERTICAL
);
481 void wxGenericScrolledWindow::CalcUnscrolledPosition(int x
, int y
, float *xx
, float *yy
) const
484 *xx
= (float)(x
+ m_xScrollPosition
* m_xScrollPixelsPerLine
);
486 *yy
= (float)(y
+ m_yScrollPosition
* m_yScrollPixelsPerLine
);
488 #endif // WXWIN_COMPATIBILITY
490 void wxGenericScrolledWindow::GetScrollPixelsPerUnit (int *x_unit
, int *y_unit
) const
493 *x_unit
= m_xScrollPixelsPerLine
;
495 *y_unit
= m_yScrollPixelsPerLine
;
498 int wxGenericScrolledWindow::GetScrollPageSize(int orient
) const
500 if ( orient
== wxHORIZONTAL
)
501 return m_xScrollLinesPerPage
;
503 return m_yScrollLinesPerPage
;
506 void wxGenericScrolledWindow::SetScrollPageSize(int orient
, int pageSize
)
508 if ( orient
== wxHORIZONTAL
)
509 m_xScrollLinesPerPage
= pageSize
;
511 m_yScrollLinesPerPage
= pageSize
;
515 * Scroll to given position (scroll position, not pixel position)
517 void wxGenericScrolledWindow::Scroll( int x_pos
, int y_pos
)
522 if (((x_pos
== -1) || (x_pos
== m_xScrollPosition
)) &&
523 ((y_pos
== -1) || (y_pos
== m_yScrollPosition
))) return;
526 m_targetWindow
->MacUpdateImmediately();
530 m_targetWindow
->GetClientSize(&w
, &h
);
532 if ((x_pos
!= -1) && (m_xScrollPixelsPerLine
))
534 int old_x
= m_xScrollPosition
;
535 m_xScrollPosition
= x_pos
;
537 // Calculate page size i.e. number of scroll units you get on the
538 // current client window
539 int noPagePositions
= (int) ( (w
/(double)m_xScrollPixelsPerLine
) + 0.5 );
540 if (noPagePositions
< 1) noPagePositions
= 1;
542 // Correct position if greater than extent of canvas minus
543 // the visible portion of it or if below zero
544 m_xScrollPosition
= wxMin( m_xScrollLines
-noPagePositions
, m_xScrollPosition
);
545 m_xScrollPosition
= wxMax( 0, m_xScrollPosition
);
547 if (old_x
!= m_xScrollPosition
) {
548 m_targetWindow
->SetScrollPos( wxHORIZONTAL
, m_xScrollPosition
, TRUE
);
549 m_targetWindow
->ScrollWindow( (old_x
-m_xScrollPosition
)*m_xScrollPixelsPerLine
, 0 );
552 if ((y_pos
!= -1) && (m_yScrollPixelsPerLine
))
554 int old_y
= m_yScrollPosition
;
555 m_yScrollPosition
= y_pos
;
557 // Calculate page size i.e. number of scroll units you get on the
558 // current client window
559 int noPagePositions
= (int) ( (h
/(double)m_yScrollPixelsPerLine
) + 0.5 );
560 if (noPagePositions
< 1) noPagePositions
= 1;
562 // Correct position if greater than extent of canvas minus
563 // the visible portion of it or if below zero
564 m_yScrollPosition
= wxMin( m_yScrollLines
-noPagePositions
, m_yScrollPosition
);
565 m_yScrollPosition
= wxMax( 0, m_yScrollPosition
);
567 if (old_y
!= m_yScrollPosition
) {
568 m_targetWindow
->SetScrollPos( wxVERTICAL
, m_yScrollPosition
, TRUE
);
569 m_targetWindow
->ScrollWindow( 0, (old_y
-m_yScrollPosition
)*m_yScrollPixelsPerLine
);
574 m_targetWindow
->MacUpdateImmediately();
579 void wxGenericScrolledWindow::EnableScrolling (bool x_scroll
, bool y_scroll
)
581 m_xScrollingEnabled
= x_scroll
;
582 m_yScrollingEnabled
= y_scroll
;
585 void wxGenericScrolledWindow::GetVirtualSize (int *x
, int *y
) const
588 *x
= m_xScrollPixelsPerLine
* m_xScrollLines
;
590 *y
= m_yScrollPixelsPerLine
* m_yScrollLines
;
593 // Where the current view starts from
594 void wxGenericScrolledWindow::GetViewStart (int *x
, int *y
) const
597 *x
= m_xScrollPosition
;
599 *y
= m_yScrollPosition
;
602 void wxGenericScrolledWindow::CalcScrolledPosition(int x
, int y
, int *xx
, int *yy
) const
605 *xx
= x
- m_xScrollPosition
* m_xScrollPixelsPerLine
;
607 *yy
= y
- m_yScrollPosition
* m_yScrollPixelsPerLine
;
610 void wxGenericScrolledWindow::CalcUnscrolledPosition(int x
, int y
, int *xx
, int *yy
) const
613 *xx
= x
+ m_xScrollPosition
* m_xScrollPixelsPerLine
;
615 *yy
= y
+ m_yScrollPosition
* m_yScrollPixelsPerLine
;
618 // ----------------------------------------------------------------------------
620 // ----------------------------------------------------------------------------
622 // Default OnSize resets scrollbars, if any
623 void wxGenericScrolledWindow::OnSize(wxSizeEvent
& WXUNUSED(event
))
625 #if wxUSE_CONSTRAINTS
633 // This calls OnDraw, having adjusted the origin according to the current
635 void wxGenericScrolledWindow::OnPaint(wxPaintEvent
& WXUNUSED(event
))
643 // kbd handling: notice that we use OnChar() and not OnKeyDown() for
644 // compatibility here - if we used OnKeyDown(), the programs which process
645 // arrows themselves in their OnChar() would never get the message and like
646 // this they always have the priority
647 void wxGenericScrolledWindow::OnChar(wxKeyEvent
& event
)
649 int stx
, sty
, // view origin
650 szx
, szy
, // view size (total)
651 clix
, cliy
; // view size (on screen)
653 ViewStart(&stx
, &sty
);
654 GetClientSize(&clix
, &cliy
);
655 GetVirtualSize(&szx
, &szy
);
657 if( m_xScrollPixelsPerLine
)
659 clix
/= m_xScrollPixelsPerLine
;
660 szx
/= m_xScrollPixelsPerLine
;
667 if( m_yScrollPixelsPerLine
)
669 cliy
/= m_yScrollPixelsPerLine
;
670 szy
/= m_yScrollPixelsPerLine
;
679 switch ( event
.KeyCode() )
683 dsty
= sty
- (5 * cliy
/ 6);
684 Scroll(-1, (dsty
== -1) ? 0 : dsty
);
689 Scroll(-1, sty
+ (5 * cliy
/ 6));
693 Scroll(0, event
.ControlDown() ? 0 : -1);
697 Scroll(szx
- clix
, event
.ControlDown() ? szy
- cliy
: -1);
723 void wxGenericScrolledWindow::OnMouseWheel(wxMouseEvent
& event
)
728 m_wheelRotation
+= event
.GetWheelRotation();
729 lines
= m_wheelRotation
/ event
.GetWheelDelta();
730 m_wheelRotation
-= lines
* event
.GetWheelDelta();
733 lines
*= event
.GetLinesPerAction();
734 GetViewStart(&vsx
, &vsy
);
735 Scroll(-1, vsy
- lines
);