]> git.saurik.com Git - wxWidgets.git/blob - src/generic/scrolwin.cpp
Motif cell highlighting problem fixed
[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
29 #if !USE_SHARED_LIBRARY
30 BEGIN_EVENT_TABLE(wxScrolledWindow, wxWindow)
31 EVT_SCROLL(wxScrolledWindow::OnScroll)
32 EVT_SIZE(wxScrolledWindow::OnSize)
33 EVT_PAINT(wxScrolledWindow::OnPaint)
34 END_EVENT_TABLE()
35
36 IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxWindow)
37 #endif
38
39 #ifdef __WXMSW__
40 #include "windows.h"
41 #endif
42
43 #ifdef __WXMOTIF__
44 // For wxRETAINED implementation
45 #include <Xm/Xm.h>
46 #endif
47
48 wxScrolledWindow::wxScrolledWindow(void)
49 {
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;
62 }
63
64 bool wxScrolledWindow::Create(wxWindow *parent, wxWindowID id,
65 const wxPoint& pos,
66 const wxSize& size,
67 long style,
68 const wxString& name)
69 {
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);
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 */
90 void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX, int pixelsPerUnitY,
91 int noUnitsX, int noUnitsY,
92 int xPos, int yPos, bool noRefresh )
93 {
94 bool do_refresh =
95 (
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)
104 );
105
106 m_xScrollPixelsPerLine = pixelsPerUnitX;
107 m_yScrollPixelsPerLine = pixelsPerUnitY;
108 m_xScrollPosition = xPos;
109 m_yScrollPosition = yPos;
110 m_xScrollLines = noUnitsX;
111 m_yScrollLines = noUnitsY;
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
145
146 AdjustScrollbars();
147
148 if (do_refresh && !noRefresh) Refresh();
149
150 #ifdef __WXMSW__
151 // Necessary?
152 UpdateWindow ((HWND) GetHWND());
153 #endif
154 }
155
156 void wxScrolledWindow::OnScroll(wxScrollEvent& event)
157 {
158 int orient = event.GetOrientation();
159
160 int nScrollInc = CalcScrollInc(event);
161 if (nScrollInc == 0) return;
162
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 }
173
174 if (orient == wxHORIZONTAL)
175 {
176 m_xScrollPosition += nScrollInc;
177 }
178 else
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 }
190 else
191 {
192 if (m_yScrollingEnabled)
193 ScrollWindow(0, -m_yScrollPixelsPerLine * nScrollInc, (const wxRect *) NULL);
194 else
195 Refresh();
196 }
197 }
198
199 int 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 {
207 case wxEVT_SCROLL_TOP:
208 {
209 if (orient == wxHORIZONTAL)
210 nScrollInc = - m_xScrollPosition;
211 else
212 nScrollInc = - m_yScrollPosition;
213 break;
214 }
215 case wxEVT_SCROLL_BOTTOM:
216 {
217 if (orient == wxHORIZONTAL)
218 nScrollInc = m_xScrollLines - m_xScrollPosition;
219 else
220 nScrollInc = m_yScrollLines - m_yScrollPosition;
221 break;
222 }
223 case wxEVT_SCROLL_LINEUP:
224 {
225 nScrollInc = -1;
226 break;
227 }
228 case wxEVT_SCROLL_LINEDOWN:
229 {
230 nScrollInc = 1;
231 break;
232 }
233 case wxEVT_SCROLL_PAGEUP:
234 {
235 if (orient == wxHORIZONTAL)
236 nScrollInc = -GetScrollPageSize(wxHORIZONTAL);
237 else
238 nScrollInc = -GetScrollPageSize(wxVERTICAL);
239 break;
240 }
241 case wxEVT_SCROLL_PAGEDOWN:
242 {
243 if (orient == wxHORIZONTAL)
244 nScrollInc = GetScrollPageSize(wxHORIZONTAL);
245 else
246 nScrollInc = GetScrollPageSize(wxVERTICAL);
247 break;
248 }
249 case wxEVT_SCROLL_THUMBTRACK:
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 }
262
263 if (orient == wxHORIZONTAL)
264 {
265 if (m_xScrollPixelsPerLine > 0) {
266 int w, h;
267 GetClientSize(&w, &h);
268
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;
273
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();
281 }
282 else
283 {
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();
300 }
301
302 return nScrollInc;
303 }
304
305 // Adjust the scrollbars - new version.
306 void wxScrolledWindow::AdjustScrollbars(void)
307 {
308 int w, h;
309 GetClientSize(&w, &h);
310
311 if (m_xScrollLines > 0)
312 {
313 // Calculate page size i.e. number of scroll units you get on the
314 // current client window
315 int noPagePositions = (int) ( (w/(float)m_xScrollPixelsPerLine) + 0.5 );
316 if (noPagePositions < 1) noPagePositions = 1;
317
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 );
322
323 SetScrollbar(wxHORIZONTAL, m_xScrollPosition, noPagePositions, m_xScrollLines);
324 // The amount by which we scroll when paging
325 SetScrollPageSize(wxHORIZONTAL, noPagePositions);
326 }
327 else
328 {
329 m_xScrollPosition = 0;
330 SetScrollbar (wxHORIZONTAL, 0, 0, 0, FALSE);
331 }
332
333 if (m_yScrollLines > 0)
334 {
335 // Calculate page size i.e. number of scroll units you get on the
336 // current client window
337 int noPagePositions = (int) ( (h/(float)m_yScrollPixelsPerLine) + 0.5 );
338 if (noPagePositions < 1) noPagePositions = 1;
339
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);
346 // The amount by which we scroll when paging
347 SetScrollPageSize(wxVERTICAL, noPagePositions);
348 }
349 else
350 {
351 m_yScrollPosition = 0;
352 SetScrollbar (wxVERTICAL, 0, 0, 0, FALSE);
353 }
354 }
355
356 // Default OnSize resets scrollbars, if any
357 void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event))
358 {
359 #if wxUSE_CONSTRAINTS
360 if (GetAutoLayout()) Layout();
361 #endif
362
363 AdjustScrollbars();
364 }
365
366 // This calls OnDraw, having adjusted the origin according to the current
367 // scroll position
368 void wxScrolledWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
369 {
370 wxPaintDC dc(this);
371 PrepareDC(dc);
372
373 OnDraw(dc);
374 }
375
376 // Override this function if you don't want to have wxScrolledWindow
377 // automatically change the origin according to the scroll position.
378 void wxScrolledWindow::PrepareDC(wxDC& dc)
379 {
380 dc.SetDeviceOrigin( -m_xScrollPosition * m_xScrollPixelsPerLine,
381 -m_yScrollPosition * m_yScrollPixelsPerLine );
382 dc.SetUserScale( m_scaleX, m_scaleY );
383 }
384
385 #if WXWIN_COMPATIBILITY
386 void wxScrolledWindow::GetScrollUnitsPerPage (int *x_page, int *y_page) const
387 {
388 *x_page = GetScrollPageSize(wxHORIZONTAL);
389 *y_page = GetScrollPageSize(wxVERTICAL);
390 }
391 #endif
392
393 void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const
394 {
395 *x_unit = m_xScrollPixelsPerLine;
396 *y_unit = m_yScrollPixelsPerLine;
397 }
398
399 int wxScrolledWindow::GetScrollPageSize(int orient) const
400 {
401 if ( orient == wxHORIZONTAL )
402 return m_xScrollLinesPerPage;
403 else
404 return m_yScrollLinesPerPage;
405 }
406
407 void 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 */
418 void wxScrolledWindow::Scroll( int x_pos, int y_pos )
419 {
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);
425
426 if (x_pos != -1)
427 {
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 );
441 }
442 if (y_pos != -1)
443 {
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 );
457 }
458
459 Refresh();
460
461 #ifdef __WXMSW__
462 // Necessary?
463 ::UpdateWindow ((HWND) GetHWND());
464 #endif
465 }
466
467 void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll)
468 {
469 m_xScrollingEnabled = x_scroll;
470 m_yScrollingEnabled = y_scroll;
471 }
472
473 void wxScrolledWindow::GetVirtualSize (int *x, int *y) const
474 {
475 *x = m_xScrollPixelsPerLine * m_xScrollLines;
476 *y = m_yScrollPixelsPerLine * m_yScrollLines;
477 }
478
479 // Where the current view starts from
480 void wxScrolledWindow::ViewStart (int *x, int *y) const
481 {
482 *x = m_xScrollPosition;
483 *y = m_yScrollPosition;
484 }
485
486 void wxScrolledWindow::CalcScrolledPosition(int x, int y, int *xx, int *yy) const
487 {
488 *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
489 *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine;
490 }
491
492 void wxScrolledWindow::CalcUnscrolledPosition(int x, int y, float *xx, float *yy) const
493 {
494 *xx = (float)(x + m_xScrollPosition * m_xScrollPixelsPerLine);
495 *yy = (float)(y + m_yScrollPosition * m_yScrollPixelsPerLine);
496 }
497
498