]> git.saurik.com Git - wxWidgets.git/blob - src/generic/scrolwin.cpp
image handlers moved to separate headers (imagbmp.h etc.) This change is backward...
[wxWidgets.git] / src / generic / scrolwin.cpp
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
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/generic/scrolwin.h"
28 #include "wx/panel.h"
29
30 BEGIN_EVENT_TABLE(wxScrolledWindow, wxPanel)
31 EVT_SCROLLWIN(wxScrolledWindow::OnScroll)
32 EVT_SIZE(wxScrolledWindow::OnSize)
33 EVT_PAINT(wxScrolledWindow::OnPaint)
34 END_EVENT_TABLE()
35
36 IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel)
37
38 #ifdef __WXMSW__
39 #include "windows.h"
40 #endif
41
42 #ifdef __WXMOTIF__
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
47 #endif
48 #include <Xm/Xm.h>
49 #ifdef __VMS__
50 # pragma message enable nosimpint
51 #endif
52 #endif
53
54 wxScrolledWindow::wxScrolledWindow()
55 {
56 m_xScrollPixelsPerLine = 0;
57 m_yScrollPixelsPerLine = 0;
58 m_xScrollingEnabled = TRUE;
59 m_yScrollingEnabled = TRUE;
60 m_xScrollPosition = 0;
61 m_yScrollPosition = 0;
62 m_xScrollLines = 0;
63 m_yScrollLines = 0;
64 m_xScrollLinesPerPage = 0;
65 m_yScrollLinesPerPage = 0;
66 m_scaleX = 1.0;
67 m_scaleY = 1.0;
68 }
69
70 bool wxScrolledWindow::Create(wxWindow *parent, wxWindowID id,
71 const wxPoint& pos,
72 const wxSize& size,
73 long style,
74 const wxString& name)
75 {
76 m_xScrollPixelsPerLine = 0;
77 m_yScrollPixelsPerLine = 0;
78 m_xScrollingEnabled = TRUE;
79 m_yScrollingEnabled = TRUE;
80 m_xScrollPosition = 0;
81 m_yScrollPosition = 0;
82 m_xScrollLines = 0;
83 m_yScrollLines = 0;
84 m_xScrollLinesPerPage = 0;
85 m_yScrollLinesPerPage = 0;
86 m_scaleX = 1.0;
87 m_scaleY = 1.0;
88
89 m_targetWindow = this;
90
91 return wxPanel::Create(parent, id, pos, size, style, name);
92 }
93
94 /*
95 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
96 * noUnitsX/noUnitsY: : no. units per scrollbar
97 */
98 void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX, int pixelsPerUnitY,
99 int noUnitsX, int noUnitsY,
100 int xPos, int yPos, bool noRefresh )
101 {
102 bool do_refresh =
103 (
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)
112 );
113
114 m_xScrollPixelsPerLine = pixelsPerUnitX;
115 m_yScrollPixelsPerLine = pixelsPerUnitY;
116 m_xScrollPosition = xPos;
117 m_yScrollPosition = yPos;
118 m_xScrollLines = noUnitsX;
119 m_yScrollLines = noUnitsY;
120
121 #ifdef __WXMOTIF__
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.
126
127 if ((m_windowStyle & wxRETAINED) == wxRETAINED)
128 {
129 Display* dpy = XtDisplay((Widget) GetMainWidget());
130
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)))
136 {
137 XFreePixmap (dpy, (Pixmap) m_backingPixmap);
138 m_backingPixmap = (WXPixmap) 0;
139 }
140
141 if (!m_backingPixmap &&
142 (noUnitsX != 0) && (noUnitsY != 0))
143 {
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);
149 }
150
151 }
152 #endif
153
154 AdjustScrollbars();
155
156 if (do_refresh && !noRefresh)
157 m_targetWindow->Refresh();
158
159 #ifdef __WXMSW__
160 // Necessary?
161 UpdateWindow ((HWND) m_targetWindow->GetHWND());
162 #endif
163 #ifdef __WXMAC__
164 m_targetWindow->MacUpdateImmediately() ;
165 #endif
166 }
167
168 wxScrolledWindow::~wxScrolledWindow()
169 {
170 }
171
172 void wxScrolledWindow::SetTargetWindow( wxWindow *target )
173 {
174 wxASSERT_MSG( target, wxT("target window must not be NULL") );
175 m_targetWindow = target;
176 }
177
178 wxWindow *wxScrolledWindow::GetTargetWindow()
179 {
180 return m_targetWindow;
181 }
182
183 void wxScrolledWindow::OnScroll(wxScrollWinEvent& event)
184 {
185 int orient = event.GetOrientation();
186
187 int nScrollInc = CalcScrollInc(event);
188 if (nScrollInc == 0) return;
189
190 if (orient == wxHORIZONTAL)
191 {
192 int newPos = m_xScrollPosition + nScrollInc;
193 SetScrollPos(wxHORIZONTAL, newPos, TRUE );
194 }
195 else
196 {
197 int newPos = m_yScrollPosition + nScrollInc;
198 SetScrollPos(wxVERTICAL, newPos, TRUE );
199 }
200
201 if (orient == wxHORIZONTAL)
202 {
203 m_xScrollPosition += nScrollInc;
204 }
205 else
206 {
207 m_yScrollPosition += nScrollInc;
208 }
209
210 if (orient == wxHORIZONTAL)
211 {
212 if (m_xScrollingEnabled)
213 m_targetWindow->ScrollWindow(-m_xScrollPixelsPerLine * nScrollInc, 0, (const wxRect *) NULL);
214 else
215 m_targetWindow->Refresh();
216 }
217 else
218 {
219 if (m_yScrollingEnabled)
220 m_targetWindow->ScrollWindow(0, -m_yScrollPixelsPerLine * nScrollInc, (const wxRect *) NULL);
221 else
222 m_targetWindow->Refresh();
223 }
224 #ifdef __WXMAC__
225 m_targetWindow->MacUpdateImmediately() ;
226 #endif
227 }
228
229 int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent& event)
230 {
231 int pos = event.GetPosition();
232 int orient = event.GetOrientation();
233
234 int nScrollInc = 0;
235 switch (event.GetEventType())
236 {
237 case wxEVT_SCROLLWIN_TOP:
238 {
239 if (orient == wxHORIZONTAL)
240 nScrollInc = - m_xScrollPosition;
241 else
242 nScrollInc = - m_yScrollPosition;
243 break;
244 }
245 case wxEVT_SCROLLWIN_BOTTOM:
246 {
247 if (orient == wxHORIZONTAL)
248 nScrollInc = m_xScrollLines - m_xScrollPosition;
249 else
250 nScrollInc = m_yScrollLines - m_yScrollPosition;
251 break;
252 }
253 case wxEVT_SCROLLWIN_LINEUP:
254 {
255 nScrollInc = -1;
256 break;
257 }
258 case wxEVT_SCROLLWIN_LINEDOWN:
259 {
260 nScrollInc = 1;
261 break;
262 }
263 case wxEVT_SCROLLWIN_PAGEUP:
264 {
265 if (orient == wxHORIZONTAL)
266 nScrollInc = -GetScrollPageSize(wxHORIZONTAL);
267 else
268 nScrollInc = -GetScrollPageSize(wxVERTICAL);
269 break;
270 }
271 case wxEVT_SCROLLWIN_PAGEDOWN:
272 {
273 if (orient == wxHORIZONTAL)
274 nScrollInc = GetScrollPageSize(wxHORIZONTAL);
275 else
276 nScrollInc = GetScrollPageSize(wxVERTICAL);
277 break;
278 }
279 case wxEVT_SCROLLWIN_THUMBTRACK:
280 {
281 if (orient == wxHORIZONTAL)
282 nScrollInc = pos - m_xScrollPosition;
283 else
284 nScrollInc = pos - m_yScrollPosition;
285 break;
286 }
287 default:
288 {
289 break;
290 }
291 }
292
293 if (orient == wxHORIZONTAL)
294 {
295 if (m_xScrollPixelsPerLine > 0)
296 {
297 int w, h;
298 m_targetWindow->GetClientSize(&w, &h);
299
300 int nMaxWidth = m_xScrollLines*m_xScrollPixelsPerLine;
301 int noPositions = (int) ( ((nMaxWidth - w)/(double)m_xScrollPixelsPerLine) + 0.5 );
302 if (noPositions < 0)
303 noPositions = 0;
304
305 if ( (m_xScrollPosition + nScrollInc) < 0 )
306 nScrollInc = -m_xScrollPosition; // As -ve as we can go
307 else if ( (m_xScrollPosition + nScrollInc) > noPositions )
308 nScrollInc = noPositions - m_xScrollPosition; // As +ve as we can go
309 }
310 else
311 m_targetWindow->Refresh();
312 }
313 else
314 {
315 if (m_yScrollPixelsPerLine > 0)
316 {
317 int w, h;
318 m_targetWindow->GetClientSize(&w, &h);
319
320 int nMaxHeight = m_yScrollLines*m_yScrollPixelsPerLine;
321 int noPositions = (int) ( ((nMaxHeight - h)/(double)m_yScrollPixelsPerLine) + 0.5 );
322 if (noPositions < 0)
323 noPositions = 0;
324
325 if ( (m_yScrollPosition + nScrollInc) < 0 )
326 nScrollInc = -m_yScrollPosition; // As -ve as we can go
327 else if ( (m_yScrollPosition + nScrollInc) > noPositions )
328 nScrollInc = noPositions - m_yScrollPosition; // As +ve as we can go
329 }
330 else
331 m_targetWindow->Refresh();
332 }
333
334 return nScrollInc;
335 }
336
337 // Adjust the scrollbars - new version.
338 void wxScrolledWindow::AdjustScrollbars()
339 {
340 int w, h;
341 m_targetWindow->GetClientSize(&w, &h);
342
343 int oldXScroll = m_xScrollPosition;
344 int oldYScroll = m_yScrollPosition;
345
346 if (m_xScrollLines > 0)
347 {
348 // Calculate page size i.e. number of scroll units you get on the
349 // current client window
350 int noPagePositions = (int) ( (w/(double)m_xScrollPixelsPerLine) + 0.5 );
351 if (noPagePositions < 1) noPagePositions = 1;
352
353 // Correct position if greater than extent of canvas minus
354 // the visible portion of it or if below zero
355 m_xScrollPosition = wxMin( m_xScrollLines-noPagePositions, m_xScrollPosition);
356 m_xScrollPosition = wxMax( 0, m_xScrollPosition );
357
358 SetScrollbar(wxHORIZONTAL, m_xScrollPosition, noPagePositions, m_xScrollLines);
359 // The amount by which we scroll when paging
360 SetScrollPageSize(wxHORIZONTAL, noPagePositions);
361 }
362 else
363 {
364 m_xScrollPosition = 0;
365 SetScrollbar (wxHORIZONTAL, 0, 0, 0, FALSE);
366 }
367
368 if (m_yScrollLines > 0)
369 {
370 // Calculate page size i.e. number of scroll units you get on the
371 // current client window
372 int noPagePositions = (int) ( (h/(double)m_yScrollPixelsPerLine) + 0.5 );
373 if (noPagePositions < 1) noPagePositions = 1;
374
375 // Correct position if greater than extent of canvas minus
376 // the visible portion of it or if below zero
377 m_yScrollPosition = wxMin( m_yScrollLines-noPagePositions, m_yScrollPosition );
378 m_yScrollPosition = wxMax( 0, m_yScrollPosition );
379
380 SetScrollbar(wxVERTICAL, m_yScrollPosition, noPagePositions, m_yScrollLines);
381 // The amount by which we scroll when paging
382 SetScrollPageSize(wxVERTICAL, noPagePositions);
383 }
384 else
385 {
386 m_yScrollPosition = 0;
387 SetScrollbar (wxVERTICAL, 0, 0, 0, FALSE);
388 }
389
390 if (oldXScroll != m_xScrollPosition)
391 {
392 if (m_xScrollingEnabled)
393 m_targetWindow->ScrollWindow( m_xScrollPixelsPerLine * (oldXScroll-m_xScrollPosition), 0, (const wxRect *) NULL );
394 else
395 m_targetWindow->Refresh();
396 }
397
398 if (oldYScroll != m_yScrollPosition)
399 {
400 if (m_yScrollingEnabled)
401 m_targetWindow->ScrollWindow( 0, m_yScrollPixelsPerLine * (oldYScroll-m_yScrollPosition), (const wxRect *) NULL );
402 else
403 m_targetWindow->Refresh();
404 }
405 }
406
407 // Default OnSize resets scrollbars, if any
408 void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event))
409 {
410 #if wxUSE_CONSTRAINTS
411 if (GetAutoLayout()) Layout();
412 #endif
413
414 AdjustScrollbars();
415 }
416
417 // This calls OnDraw, having adjusted the origin according to the current
418 // scroll position
419 void wxScrolledWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
420 {
421 wxPaintDC dc(this);
422 PrepareDC(dc);
423
424 OnDraw(dc);
425 }
426
427 // Override this function if you don't want to have wxScrolledWindow
428 // automatically change the origin according to the scroll position.
429 void wxScrolledWindow::PrepareDC(wxDC& dc)
430 {
431 dc.SetDeviceOrigin( -m_xScrollPosition * m_xScrollPixelsPerLine,
432 -m_yScrollPosition * m_yScrollPixelsPerLine );
433 dc.SetUserScale( m_scaleX, m_scaleY );
434 }
435
436 #if WXWIN_COMPATIBILITY
437 void wxScrolledWindow::GetScrollUnitsPerPage (int *x_page, int *y_page) const
438 {
439 *x_page = GetScrollPageSize(wxHORIZONTAL);
440 *y_page = GetScrollPageSize(wxVERTICAL);
441 }
442
443 void wxScrolledWindow::CalcUnscrolledPosition(int x, int y, float *xx, float *yy) const
444 {
445 if ( xx )
446 *xx = (float)(x + m_xScrollPosition * m_xScrollPixelsPerLine);
447 if ( yy )
448 *yy = (float)(y + m_yScrollPosition * m_yScrollPixelsPerLine);
449 }
450 #endif // WXWIN_COMPATIBILITY
451
452 void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const
453 {
454 if ( x_unit )
455 *x_unit = m_xScrollPixelsPerLine;
456 if ( y_unit )
457 *y_unit = m_yScrollPixelsPerLine;
458 }
459
460 int wxScrolledWindow::GetScrollPageSize(int orient) const
461 {
462 if ( orient == wxHORIZONTAL )
463 return m_xScrollLinesPerPage;
464 else
465 return m_yScrollLinesPerPage;
466 }
467
468 void wxScrolledWindow::SetScrollPageSize(int orient, int pageSize)
469 {
470 if ( orient == wxHORIZONTAL )
471 m_xScrollLinesPerPage = pageSize;
472 else
473 m_yScrollLinesPerPage = pageSize;
474 }
475
476 /*
477 * Scroll to given position (scroll position, not pixel position)
478 */
479 void wxScrolledWindow::Scroll( int x_pos, int y_pos )
480 {
481 if (((x_pos == -1) || (x_pos == m_xScrollPosition)) &&
482 ((y_pos == -1) || (y_pos == m_yScrollPosition))) return;
483
484 int w, h;
485 m_targetWindow->GetClientSize(&w, &h);
486
487 if (x_pos != -1)
488 {
489 int old_x = m_xScrollPosition;
490 m_xScrollPosition = x_pos;
491
492 // Calculate page size i.e. number of scroll units you get on the
493 // current client window
494 int noPagePositions = (int) ( (w/(double)m_xScrollPixelsPerLine) + 0.5 );
495 if (noPagePositions < 1) noPagePositions = 1;
496
497 // Correct position if greater than extent of canvas minus
498 // the visible portion of it or if below zero
499 m_xScrollPosition = wxMin( m_xScrollLines-noPagePositions, m_xScrollPosition );
500 m_xScrollPosition = wxMax( 0, m_xScrollPosition );
501
502 m_targetWindow->SetScrollPos( wxHORIZONTAL, m_xScrollPosition, TRUE );
503
504 m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 );
505 }
506 if (y_pos != -1)
507 {
508 int old_y = m_yScrollPosition;
509 m_yScrollPosition = y_pos;
510
511 // Calculate page size i.e. number of scroll units you get on the
512 // current client window
513 int noPagePositions = (int) ( (h/(double)m_yScrollPixelsPerLine) + 0.5 );
514 if (noPagePositions < 1) noPagePositions = 1;
515
516 // Correct position if greater than extent of canvas minus
517 // the visible portion of it or if below zero
518 m_yScrollPosition = wxMin( m_yScrollLines-noPagePositions, m_yScrollPosition );
519 m_yScrollPosition = wxMax( 0, m_yScrollPosition );
520
521 m_targetWindow->SetScrollPos( wxVERTICAL, m_yScrollPosition, TRUE );
522
523 m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine );
524 }
525
526
527 #ifdef __WXMSW__
528 // ::UpdateWindow ((HWND) GetHWND());
529 #else
530 // Refresh();
531 #endif
532 #ifdef __WXMAC__
533 m_targetWindow->MacUpdateImmediately() ;
534 #endif
535 }
536
537 void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll)
538 {
539 m_xScrollingEnabled = x_scroll;
540 m_yScrollingEnabled = y_scroll;
541 }
542
543 void wxScrolledWindow::GetVirtualSize (int *x, int *y) const
544 {
545 if ( x )
546 *x = m_xScrollPixelsPerLine * m_xScrollLines;
547 if ( y )
548 *y = m_yScrollPixelsPerLine * m_yScrollLines;
549 }
550
551 // Where the current view starts from
552 void wxScrolledWindow::ViewStart (int *x, int *y) const
553 {
554 if ( x )
555 *x = m_xScrollPosition;
556 if ( y )
557 *y = m_yScrollPosition;
558 }
559
560 void wxScrolledWindow::CalcScrolledPosition(int x, int y, int *xx, int *yy) const
561 {
562 if ( xx )
563 *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
564 if ( yy )
565 *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine;
566 }
567
568 void wxScrolledWindow::CalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
569 {
570 if ( xx )
571 *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine;
572 if ( yy )
573 *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine;
574 }