]> git.saurik.com Git - wxWidgets.git/blob - src/generic/scrolwin.cpp
fixed SetLink (if link.Href is empty, nulls the link
[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 // 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.
165
166 // Necessary?
167 // UpdateWindow ((HWND) m_targetWindow->GetHWND());
168 #endif
169 #ifdef __WXMAC__
170 m_targetWindow->MacUpdateImmediately() ;
171 #endif
172 }
173
174 wxScrolledWindow::~wxScrolledWindow()
175 {
176 }
177
178 void wxScrolledWindow::SetTargetWindow( wxWindow *target )
179 {
180 wxASSERT_MSG( target, wxT("target window must not be NULL") );
181 m_targetWindow = target;
182 }
183
184 wxWindow *wxScrolledWindow::GetTargetWindow()
185 {
186 return m_targetWindow;
187 }
188
189 void wxScrolledWindow::OnScroll(wxScrollWinEvent& event)
190 {
191 int orient = event.GetOrientation();
192
193 int nScrollInc = CalcScrollInc(event);
194 if (nScrollInc == 0) return;
195
196 if (orient == wxHORIZONTAL)
197 {
198 int newPos = m_xScrollPosition + nScrollInc;
199 SetScrollPos(wxHORIZONTAL, newPos, TRUE );
200 }
201 else
202 {
203 int newPos = m_yScrollPosition + nScrollInc;
204 SetScrollPos(wxVERTICAL, newPos, TRUE );
205 }
206
207 if (orient == wxHORIZONTAL)
208 {
209 m_xScrollPosition += nScrollInc;
210 }
211 else
212 {
213 m_yScrollPosition += nScrollInc;
214 }
215
216 if (orient == wxHORIZONTAL)
217 {
218 if (m_xScrollingEnabled)
219 m_targetWindow->ScrollWindow(-m_xScrollPixelsPerLine * nScrollInc, 0, (const wxRect *) NULL);
220 else
221 m_targetWindow->Refresh();
222 }
223 else
224 {
225 if (m_yScrollingEnabled)
226 m_targetWindow->ScrollWindow(0, -m_yScrollPixelsPerLine * nScrollInc, (const wxRect *) NULL);
227 else
228 m_targetWindow->Refresh();
229 }
230 #ifdef __WXMAC__
231 m_targetWindow->MacUpdateImmediately() ;
232 #endif
233 }
234
235 int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent& event)
236 {
237 int pos = event.GetPosition();
238 int orient = event.GetOrientation();
239
240 int nScrollInc = 0;
241 switch (event.GetEventType())
242 {
243 case wxEVT_SCROLLWIN_TOP:
244 {
245 if (orient == wxHORIZONTAL)
246 nScrollInc = - m_xScrollPosition;
247 else
248 nScrollInc = - m_yScrollPosition;
249 break;
250 }
251 case wxEVT_SCROLLWIN_BOTTOM:
252 {
253 if (orient == wxHORIZONTAL)
254 nScrollInc = m_xScrollLines - m_xScrollPosition;
255 else
256 nScrollInc = m_yScrollLines - m_yScrollPosition;
257 break;
258 }
259 case wxEVT_SCROLLWIN_LINEUP:
260 {
261 nScrollInc = -1;
262 break;
263 }
264 case wxEVT_SCROLLWIN_LINEDOWN:
265 {
266 nScrollInc = 1;
267 break;
268 }
269 case wxEVT_SCROLLWIN_PAGEUP:
270 {
271 if (orient == wxHORIZONTAL)
272 nScrollInc = -GetScrollPageSize(wxHORIZONTAL);
273 else
274 nScrollInc = -GetScrollPageSize(wxVERTICAL);
275 break;
276 }
277 case wxEVT_SCROLLWIN_PAGEDOWN:
278 {
279 if (orient == wxHORIZONTAL)
280 nScrollInc = GetScrollPageSize(wxHORIZONTAL);
281 else
282 nScrollInc = GetScrollPageSize(wxVERTICAL);
283 break;
284 }
285 case wxEVT_SCROLLWIN_THUMBTRACK:
286 {
287 if (orient == wxHORIZONTAL)
288 nScrollInc = pos - m_xScrollPosition;
289 else
290 nScrollInc = pos - m_yScrollPosition;
291 break;
292 }
293 default:
294 {
295 break;
296 }
297 }
298
299 if (orient == wxHORIZONTAL)
300 {
301 if (m_xScrollPixelsPerLine > 0)
302 {
303 int w, h;
304 m_targetWindow->GetClientSize(&w, &h);
305
306 int nMaxWidth = m_xScrollLines*m_xScrollPixelsPerLine;
307 int noPositions = (int) ( ((nMaxWidth - w)/(double)m_xScrollPixelsPerLine) + 0.5 );
308 if (noPositions < 0)
309 noPositions = 0;
310
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
315 }
316 else
317 m_targetWindow->Refresh();
318 }
319 else
320 {
321 if (m_yScrollPixelsPerLine > 0)
322 {
323 int w, h;
324 m_targetWindow->GetClientSize(&w, &h);
325
326 int nMaxHeight = m_yScrollLines*m_yScrollPixelsPerLine;
327 int noPositions = (int) ( ((nMaxHeight - h)/(double)m_yScrollPixelsPerLine) + 0.5 );
328 if (noPositions < 0)
329 noPositions = 0;
330
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
335 }
336 else
337 m_targetWindow->Refresh();
338 }
339
340 return nScrollInc;
341 }
342
343 // Adjust the scrollbars - new version.
344 void wxScrolledWindow::AdjustScrollbars()
345 {
346 int w, h;
347 m_targetWindow->GetClientSize(&w, &h);
348
349 int oldXScroll = m_xScrollPosition;
350 int oldYScroll = m_yScrollPosition;
351
352 if (m_xScrollLines > 0)
353 {
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;
358
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 );
363
364 SetScrollbar(wxHORIZONTAL, m_xScrollPosition, noPagePositions, m_xScrollLines);
365 // The amount by which we scroll when paging
366 SetScrollPageSize(wxHORIZONTAL, noPagePositions);
367 }
368 else
369 {
370 m_xScrollPosition = 0;
371 SetScrollbar (wxHORIZONTAL, 0, 0, 0, FALSE);
372 }
373
374 if (m_yScrollLines > 0)
375 {
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;
380
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 );
385
386 SetScrollbar(wxVERTICAL, m_yScrollPosition, noPagePositions, m_yScrollLines);
387 // The amount by which we scroll when paging
388 SetScrollPageSize(wxVERTICAL, noPagePositions);
389 }
390 else
391 {
392 m_yScrollPosition = 0;
393 SetScrollbar (wxVERTICAL, 0, 0, 0, FALSE);
394 }
395
396 if (oldXScroll != m_xScrollPosition)
397 {
398 if (m_xScrollingEnabled)
399 m_targetWindow->ScrollWindow( m_xScrollPixelsPerLine * (oldXScroll-m_xScrollPosition), 0, (const wxRect *) NULL );
400 else
401 m_targetWindow->Refresh();
402 }
403
404 if (oldYScroll != m_yScrollPosition)
405 {
406 if (m_yScrollingEnabled)
407 m_targetWindow->ScrollWindow( 0, m_yScrollPixelsPerLine * (oldYScroll-m_yScrollPosition), (const wxRect *) NULL );
408 else
409 m_targetWindow->Refresh();
410 }
411 }
412
413 // Default OnSize resets scrollbars, if any
414 void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event))
415 {
416 #if wxUSE_CONSTRAINTS
417 if (GetAutoLayout()) Layout();
418 #endif
419
420 AdjustScrollbars();
421 }
422
423 // This calls OnDraw, having adjusted the origin according to the current
424 // scroll position
425 void wxScrolledWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
426 {
427 wxPaintDC dc(this);
428 PrepareDC(dc);
429
430 OnDraw(dc);
431 }
432
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)
436 {
437 dc.SetDeviceOrigin( -m_xScrollPosition * m_xScrollPixelsPerLine,
438 -m_yScrollPosition * m_yScrollPixelsPerLine );
439 dc.SetUserScale( m_scaleX, m_scaleY );
440 }
441
442 #if WXWIN_COMPATIBILITY
443 void wxScrolledWindow::GetScrollUnitsPerPage (int *x_page, int *y_page) const
444 {
445 *x_page = GetScrollPageSize(wxHORIZONTAL);
446 *y_page = GetScrollPageSize(wxVERTICAL);
447 }
448
449 void wxScrolledWindow::CalcUnscrolledPosition(int x, int y, float *xx, float *yy) const
450 {
451 if ( xx )
452 *xx = (float)(x + m_xScrollPosition * m_xScrollPixelsPerLine);
453 if ( yy )
454 *yy = (float)(y + m_yScrollPosition * m_yScrollPixelsPerLine);
455 }
456 #endif // WXWIN_COMPATIBILITY
457
458 void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const
459 {
460 if ( x_unit )
461 *x_unit = m_xScrollPixelsPerLine;
462 if ( y_unit )
463 *y_unit = m_yScrollPixelsPerLine;
464 }
465
466 int wxScrolledWindow::GetScrollPageSize(int orient) const
467 {
468 if ( orient == wxHORIZONTAL )
469 return m_xScrollLinesPerPage;
470 else
471 return m_yScrollLinesPerPage;
472 }
473
474 void wxScrolledWindow::SetScrollPageSize(int orient, int pageSize)
475 {
476 if ( orient == wxHORIZONTAL )
477 m_xScrollLinesPerPage = pageSize;
478 else
479 m_yScrollLinesPerPage = pageSize;
480 }
481
482 /*
483 * Scroll to given position (scroll position, not pixel position)
484 */
485 void wxScrolledWindow::Scroll( int x_pos, int y_pos )
486 {
487 if (((x_pos == -1) || (x_pos == m_xScrollPosition)) &&
488 ((y_pos == -1) || (y_pos == m_yScrollPosition))) return;
489
490 int w, h;
491 m_targetWindow->GetClientSize(&w, &h);
492
493 if (x_pos != -1)
494 {
495 int old_x = m_xScrollPosition;
496 m_xScrollPosition = x_pos;
497
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;
502
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 );
507
508 m_targetWindow->SetScrollPos( wxHORIZONTAL, m_xScrollPosition, TRUE );
509
510 m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 );
511 }
512 if (y_pos != -1)
513 {
514 int old_y = m_yScrollPosition;
515 m_yScrollPosition = y_pos;
516
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;
521
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 );
526
527 m_targetWindow->SetScrollPos( wxVERTICAL, m_yScrollPosition, TRUE );
528
529 m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine );
530 }
531
532
533 #ifdef __WXMAC__
534 m_targetWindow->MacUpdateImmediately() ;
535 #endif
536 }
537
538 void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll)
539 {
540 m_xScrollingEnabled = x_scroll;
541 m_yScrollingEnabled = y_scroll;
542 }
543
544 void wxScrolledWindow::GetVirtualSize (int *x, int *y) const
545 {
546 if ( x )
547 *x = m_xScrollPixelsPerLine * m_xScrollLines;
548 if ( y )
549 *y = m_yScrollPixelsPerLine * m_yScrollLines;
550 }
551
552 // Where the current view starts from
553 void wxScrolledWindow::GetViewStart (int *x, int *y) const
554 {
555 if ( x )
556 *x = m_xScrollPosition;
557 if ( y )
558 *y = m_yScrollPosition;
559 }
560
561 void wxScrolledWindow::CalcScrolledPosition(int x, int y, int *xx, int *yy) const
562 {
563 if ( xx )
564 *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
565 if ( yy )
566 *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine;
567 }
568
569 void wxScrolledWindow::CalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
570 {
571 if ( xx )
572 *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine;
573 if ( yy )
574 *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine;
575 }