]> git.saurik.com Git - wxWidgets.git/blame - src/generic/scrolwin.cpp
CW Win32 and Mac adaptions
[wxWidgets.git] / src / generic / scrolwin.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: scrolwin.cpp
3// Purpose: wxScrolledWindow implementation
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation
14#pragma implementation "scrolwin.h"
15#endif
16
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
19
20#include "wx/utils.h"
21#include "wx/dcclient.h"
22
c801d85f
KB
23#ifdef __BORLANDC__
24#pragma hdrstop
25#endif
26
27#include "wx/generic/scrolwin.h"
28
29#if !USE_SHARED_LIBRARY
30BEGIN_EVENT_TABLE(wxScrolledWindow, wxWindow)
139adb6a
RR
31 EVT_SCROLL(wxScrolledWindow::OnScroll)
32 EVT_SIZE(wxScrolledWindow::OnSize)
33 EVT_PAINT(wxScrolledWindow::OnPaint)
c801d85f
KB
34END_EVENT_TABLE()
35
36IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxWindow)
37#endif
38
48d1144b
JS
39#ifdef __WXMSW__
40#include "windows.h"
41#endif
42
a91b47e8
JS
43#ifdef __WXMOTIF__
44// For wxRETAINED implementation
45#include <Xm/Xm.h>
46#endif
47
c801d85f
KB
48wxScrolledWindow::wxScrolledWindow(void)
49{
139adb6a
RR
50 m_xScrollPixelsPerLine = 0;
51 m_yScrollPixelsPerLine = 0;
52 m_xScrollingEnabled = TRUE;
53 m_yScrollingEnabled = TRUE;
54 m_xScrollPosition = 0;
55 m_yScrollPosition = 0;
56 m_xScrollLines = 0;
57 m_yScrollLines = 0;
58 m_xScrollLinesPerPage = 0;
59 m_yScrollLinesPerPage = 0;
60 m_scaleX = 1.0;
61 m_scaleY = 1.0;
c801d85f
KB
62}
63
debe6624 64bool wxScrolledWindow::Create(wxWindow *parent, wxWindowID id,
c801d85f
KB
65 const wxPoint& pos,
66 const wxSize& size,
debe6624 67 long style,
c801d85f
KB
68 const wxString& name)
69{
139adb6a
RR
70 m_xScrollPixelsPerLine = 0;
71 m_yScrollPixelsPerLine = 0;
72 m_xScrollingEnabled = TRUE;
73 m_yScrollingEnabled = TRUE;
74 m_xScrollPosition = 0;
75 m_yScrollPosition = 0;
76 m_xScrollLines = 0;
77 m_yScrollLines = 0;
78 m_xScrollLinesPerPage = 0;
79 m_yScrollLinesPerPage = 0;
80 m_scaleX = 1.0;
81 m_scaleY = 1.0;
82
83 return wxWindow::Create(parent, id, pos, size, style, name);
c801d85f
KB
84}
85
86/*
87 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
88 * noUnitsX/noUnitsY: : no. units per scrollbar
89 */
debe6624
JS
90void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX, int pixelsPerUnitY,
91 int noUnitsX, int noUnitsY,
92 int xPos, int yPos, bool noRefresh )
c801d85f 93{
139adb6a
RR
94 bool do_refresh =
95 (
c801d85f
KB
96 (noUnitsX != 0 && m_xScrollLines == 0) ||
97 (noUnitsX < m_xScrollPosition) ||
98 (noUnitsY != 0 && m_yScrollLines == 0) ||
99 (noUnitsY < m_yScrollPosition) ||
100 (xPos != m_xScrollPosition) ||
101 (yPos != m_yScrollPosition) ||
102 (pixelsPerUnitX != m_xScrollPixelsPerLine) ||
103 (pixelsPerUnitY != m_yScrollPixelsPerLine)
139adb6a 104 );
c801d85f 105
139adb6a
RR
106 m_xScrollPixelsPerLine = pixelsPerUnitX;
107 m_yScrollPixelsPerLine = pixelsPerUnitY;
108 m_xScrollPosition = xPos;
109 m_yScrollPosition = yPos;
110 m_xScrollLines = noUnitsX;
111 m_yScrollLines = noUnitsY;
a91b47e8
JS
112
113#ifdef __WXMOTIF__
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.
118
119 if ((m_windowStyle & wxRETAINED) == wxRETAINED)
120 {
121 Display* dpy = XtDisplay((Widget) GetMainWidget());
122
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)))
128 {
129 XFreePixmap (dpy, (Pixmap) m_backingPixmap);
130 m_backingPixmap = (WXPixmap) 0;
131 }
132
133 if (!m_backingPixmap &&
134 (noUnitsX != 0) && (noUnitsY != 0))
135 {
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);
141 }
142
143 }
144#endif
d4c99d6f 145
139adb6a 146 AdjustScrollbars();
c801d85f
KB
147
148 if (do_refresh && !noRefresh) Refresh();
149
2049ba38 150#ifdef __WXMSW__
48d1144b 151 // Necessary?
c801d85f
KB
152 UpdateWindow ((HWND) GetHWND());
153#endif
154}
155
156void wxScrolledWindow::OnScroll(wxScrollEvent& event)
157{
139adb6a 158 int orient = event.GetOrientation();
c801d85f 159
139adb6a
RR
160 int nScrollInc = CalcScrollInc(event);
161 if (nScrollInc == 0) return;
c801d85f 162
139adb6a
RR
163 if (orient == wxHORIZONTAL)
164 {
165 int newPos = m_xScrollPosition + nScrollInc;
166 SetScrollPos(wxHORIZONTAL, newPos, TRUE );
167 }
168 else
169 {
170 int newPos = m_yScrollPosition + nScrollInc;
171 SetScrollPos(wxVERTICAL, newPos, TRUE );
172 }
c801d85f 173
139adb6a
RR
174 if (orient == wxHORIZONTAL)
175 {
176 m_xScrollPosition += nScrollInc;
177 }
c801d85f 178 else
139adb6a
RR
179 {
180 m_yScrollPosition += nScrollInc;
181 }
182
183 if (orient == wxHORIZONTAL)
184 {
185 if (m_xScrollingEnabled)
186 ScrollWindow(-m_xScrollPixelsPerLine * nScrollInc, 0, (const wxRect *) NULL);
187 else
188 Refresh();
189 }
c801d85f 190 else
139adb6a
RR
191 {
192 if (m_yScrollingEnabled)
193 ScrollWindow(0, -m_yScrollPixelsPerLine * nScrollInc, (const wxRect *) NULL);
194 else
195 Refresh();
c801d85f 196 }
c801d85f
KB
197}
198
199int wxScrolledWindow::CalcScrollInc(wxScrollEvent& event)
200{
201 int pos = event.GetPosition();
202 int orient = event.GetOrientation();
203
204 int nScrollInc = 0;
205 switch (event.GetEventType())
206 {
f5419957 207 case wxEVT_SCROLL_TOP:
c801d85f
KB
208 {
209 if (orient == wxHORIZONTAL)
210 nScrollInc = - m_xScrollPosition;
211 else
212 nScrollInc = - m_yScrollPosition;
213 break;
214 }
f5419957 215 case wxEVT_SCROLL_BOTTOM:
c801d85f
KB
216 {
217 if (orient == wxHORIZONTAL)
218 nScrollInc = m_xScrollLines - m_xScrollPosition;
219 else
220 nScrollInc = m_yScrollLines - m_yScrollPosition;
221 break;
222 }
f5419957 223 case wxEVT_SCROLL_LINEUP:
c801d85f
KB
224 {
225 nScrollInc = -1;
226 break;
227 }
f5419957 228 case wxEVT_SCROLL_LINEDOWN:
c801d85f
KB
229 {
230 nScrollInc = 1;
231 break;
232 }
f5419957 233 case wxEVT_SCROLL_PAGEUP:
c801d85f
KB
234 {
235 if (orient == wxHORIZONTAL)
236 nScrollInc = -GetScrollPageSize(wxHORIZONTAL);
237 else
238 nScrollInc = -GetScrollPageSize(wxVERTICAL);
239 break;
240 }
f5419957 241 case wxEVT_SCROLL_PAGEDOWN:
c801d85f
KB
242 {
243 if (orient == wxHORIZONTAL)
244 nScrollInc = GetScrollPageSize(wxHORIZONTAL);
245 else
246 nScrollInc = GetScrollPageSize(wxVERTICAL);
247 break;
248 }
f5419957 249 case wxEVT_SCROLL_THUMBTRACK:
c801d85f
KB
250 {
251 if (orient == wxHORIZONTAL)
252 nScrollInc = pos - m_xScrollPosition;
253 else
254 nScrollInc = pos - m_yScrollPosition;
255 break;
256 }
257 default:
258 {
259 break;
260 }
261 }
88150e60 262
c801d85f
KB
263 if (orient == wxHORIZONTAL)
264 {
9d9355c6
VZ
265 if (m_xScrollPixelsPerLine > 0) {
266 int w, h;
267 GetClientSize(&w, &h);
c801d85f 268
9d9355c6
VZ
269 int nMaxWidth = m_xScrollLines*m_xScrollPixelsPerLine;
270 int noPositions = (int) ( ((nMaxWidth - w)/(float)m_xScrollPixelsPerLine) + 0.5 );
271 if (noPositions < 0)
272 noPositions = 0;
c801d85f 273
9d9355c6
VZ
274 if ( (m_xScrollPosition + nScrollInc) < 0 )
275 nScrollInc = -m_xScrollPosition; // As -ve as we can go
276 else if ( (m_xScrollPosition + nScrollInc) > noPositions )
277 nScrollInc = noPositions - m_xScrollPosition; // As +ve as we can go
278 }
279 else
280 Refresh();
c801d85f
KB
281 }
282 else
283 {
9d9355c6
VZ
284 if (m_yScrollPixelsPerLine > 0) {
285 int w, h;
286 GetClientSize(&w, &h);
287
288 int nMaxHeight = m_yScrollLines*m_yScrollPixelsPerLine;
289 int noPositions = (int) ( ((nMaxHeight - h)/(float)m_yScrollPixelsPerLine) + 0.5 );
290 if (noPositions < 0)
291 noPositions = 0;
292
293 if ( (m_yScrollPosition + nScrollInc) < 0 )
294 nScrollInc = -m_yScrollPosition; // As -ve as we can go
295 else if ( (m_yScrollPosition + nScrollInc) > noPositions )
296 nScrollInc = noPositions - m_yScrollPosition; // As +ve as we can go
297 }
298 else
299 Refresh();
c801d85f 300 }
9d9355c6
VZ
301
302 return nScrollInc;
c801d85f
KB
303}
304
305// Adjust the scrollbars - new version.
306void wxScrolledWindow::AdjustScrollbars(void)
307{
139adb6a
RR
308 int w, h;
309 GetClientSize(&w, &h);
c801d85f 310
139adb6a
RR
311 if (m_xScrollLines > 0)
312 {
c801d85f
KB
313 // Calculate page size i.e. number of scroll units you get on the
314 // current client window
139adb6a
RR
315 int noPagePositions = (int) ( (w/(float)m_xScrollPixelsPerLine) + 0.5 );
316 if (noPagePositions < 1) noPagePositions = 1;
c801d85f 317
139adb6a
RR
318 // Correct position if greater than extent of canvas minus
319 // the visible portion of it or if below zero
320 m_xScrollPosition = wxMin( m_xScrollLines-noPagePositions, m_xScrollPosition);
321 m_xScrollPosition = wxMax( 0, m_xScrollPosition );
c801d85f 322
139adb6a 323 SetScrollbar(wxHORIZONTAL, m_xScrollPosition, noPagePositions, m_xScrollLines);
88150e60
JS
324 // The amount by which we scroll when paging
325 SetScrollPageSize(wxHORIZONTAL, noPagePositions);
139adb6a
RR
326 }
327 else
328 {
329 m_xScrollPosition = 0;
330 SetScrollbar (wxHORIZONTAL, 0, 0, 0, FALSE);
331 }
332
333 if (m_yScrollLines > 0)
334 {
c801d85f
KB
335 // Calculate page size i.e. number of scroll units you get on the
336 // current client window
139adb6a
RR
337 int noPagePositions = (int) ( (h/(float)m_yScrollPixelsPerLine) + 0.5 );
338 if (noPagePositions < 1) noPagePositions = 1;
c801d85f 339
139adb6a
RR
340 // Correct position if greater than extent of canvas minus
341 // the visible portion of it or if below zero
342 m_yScrollPosition = wxMin( m_yScrollLines-noPagePositions, m_yScrollPosition );
343 m_yScrollPosition = wxMax( 0, m_yScrollPosition );
344
345 SetScrollbar(wxVERTICAL, m_yScrollPosition, noPagePositions, m_yScrollLines);
88150e60
JS
346 // The amount by which we scroll when paging
347 SetScrollPageSize(wxVERTICAL, noPagePositions);
139adb6a
RR
348 }
349 else
350 {
351 m_yScrollPosition = 0;
352 SetScrollbar (wxVERTICAL, 0, 0, 0, FALSE);
353 }
c801d85f
KB
354}
355
356// Default OnSize resets scrollbars, if any
357void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event))
358{
47d67540 359#if wxUSE_CONSTRAINTS
139adb6a 360 if (GetAutoLayout()) Layout();
c801d85f
KB
361#endif
362
139adb6a 363 AdjustScrollbars();
c801d85f
KB
364}
365
366// This calls OnDraw, having adjusted the origin according to the current
367// scroll position
368void wxScrolledWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
369{
139adb6a
RR
370 wxPaintDC dc(this);
371 PrepareDC(dc);
c801d85f 372
139adb6a 373 OnDraw(dc);
c801d85f
KB
374}
375
376// Override this function if you don't want to have wxScrolledWindow
377// automatically change the origin according to the scroll position.
378void wxScrolledWindow::PrepareDC(wxDC& dc)
379{
139adb6a
RR
380 dc.SetDeviceOrigin( -m_xScrollPosition * m_xScrollPixelsPerLine,
381 -m_yScrollPosition * m_yScrollPixelsPerLine );
382 dc.SetUserScale( m_scaleX, m_scaleY );
c801d85f
KB
383}
384
385#if WXWIN_COMPATIBILITY
386void wxScrolledWindow::GetScrollUnitsPerPage (int *x_page, int *y_page) const
387{
388 *x_page = GetScrollPageSize(wxHORIZONTAL);
389 *y_page = GetScrollPageSize(wxVERTICAL);
390}
391#endif
392
393void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const
394{
395 *x_unit = m_xScrollPixelsPerLine;
396 *y_unit = m_yScrollPixelsPerLine;
397}
398
399int wxScrolledWindow::GetScrollPageSize(int orient) const
400{
401 if ( orient == wxHORIZONTAL )
402 return m_xScrollLinesPerPage;
403 else
404 return m_yScrollLinesPerPage;
405}
406
407void wxScrolledWindow::SetScrollPageSize(int orient, int pageSize)
408{
409 if ( orient == wxHORIZONTAL )
410 m_xScrollLinesPerPage = pageSize;
411 else
412 m_yScrollLinesPerPage = pageSize;
413}
414
415/*
416 * Scroll to given position (scroll position, not pixel position)
417 */
139adb6a 418void wxScrolledWindow::Scroll( int x_pos, int y_pos )
c801d85f 419{
139adb6a
RR
420 if (((x_pos == -1) || (x_pos == m_xScrollPosition)) &&
421 ((y_pos == -1) || (y_pos == m_yScrollPosition))) return;
422
423 int w, h;
424 GetClientSize(&w, &h);
c801d85f 425
139adb6a 426 if (x_pos != -1)
c801d85f 427 {
139adb6a
RR
428 m_xScrollPosition = x_pos;
429
430 // Calculate page size i.e. number of scroll units you get on the
431 // current client window
432 int noPagePositions = (int) ( (w/(float)m_xScrollPixelsPerLine) + 0.5 );
433 if (noPagePositions < 1) noPagePositions = 1;
434
435 // Correct position if greater than extent of canvas minus
436 // the visible portion of it or if below zero
437 m_xScrollPosition = wxMin( m_xScrollLines-noPagePositions, m_xScrollPosition );
438 m_xScrollPosition = wxMax( 0, m_xScrollPosition );
439
440 SetScrollPos( wxHORIZONTAL, m_xScrollPosition, TRUE );
c801d85f 441 }
139adb6a 442 if (y_pos != -1)
c801d85f 443 {
139adb6a
RR
444 m_yScrollPosition = y_pos;
445
446 // Calculate page size i.e. number of scroll units you get on the
447 // current client window
448 int noPagePositions = (int) ( (h/(float)m_yScrollPixelsPerLine) + 0.5 );
449 if (noPagePositions < 1) noPagePositions = 1;
450
451 // Correct position if greater than extent of canvas minus
452 // the visible portion of it or if below zero
453 m_yScrollPosition = wxMin( m_yScrollLines-noPagePositions, m_yScrollPosition );
454 m_yScrollPosition = wxMax( 0, m_yScrollPosition );
455
456 SetScrollPos( wxVERTICAL, m_yScrollPosition, TRUE );
c801d85f 457 }
139adb6a
RR
458
459 Refresh();
460
2049ba38 461#ifdef __WXMSW__
48d1144b 462 // Necessary?
139adb6a 463 ::UpdateWindow ((HWND) GetHWND());
c801d85f
KB
464#endif
465}
466
debe6624 467void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll)
c801d85f 468{
139adb6a
RR
469 m_xScrollingEnabled = x_scroll;
470 m_yScrollingEnabled = y_scroll;
c801d85f
KB
471}
472
473void wxScrolledWindow::GetVirtualSize (int *x, int *y) const
474{
139adb6a
RR
475 *x = m_xScrollPixelsPerLine * m_xScrollLines;
476 *y = m_yScrollPixelsPerLine * m_yScrollLines;
c801d85f
KB
477}
478
479// Where the current view starts from
480void wxScrolledWindow::ViewStart (int *x, int *y) const
481{
139adb6a
RR
482 *x = m_xScrollPosition;
483 *y = m_yScrollPosition;
c801d85f
KB
484}
485
debe6624 486void wxScrolledWindow::CalcScrolledPosition(int x, int y, int *xx, int *yy) const
c801d85f 487{
139adb6a
RR
488 *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
489 *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine;
c801d85f
KB
490}
491
debe6624 492void wxScrolledWindow::CalcUnscrolledPosition(int x, int y, float *xx, float *yy) const
c801d85f 493{
139adb6a
RR
494 *xx = (float)(x + m_xScrollPosition * m_xScrollPixelsPerLine);
495 *yy = (float)(y + m_yScrollPosition * m_yScrollPixelsPerLine);
c801d85f
KB
496}
497
498