/[pcsx2_0.9.7]/branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/generic/scrlwing.cpp
ViewVC logotype

Contents of /branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/generic/scrlwing.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations) (download)
Tue Sep 7 03:29:01 2010 UTC (9 years, 11 months ago) by william
File size: 47563 byte(s)
branching from upstream revision (http://pcsx2.googlecode.com/svn/trunk
): r3113 to
https://svn.netsolutions.dnsalias.com/websvn/ps2/pcsx2/pcsx2_0.9.7/branch/r3113_0.9.7_beta
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/scrlwing.cpp
3 // Purpose: wxScrolledWindow implementation
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin on 31.08.00: wxScrollHelper allows to implement.
6 // Ron Lee on 10.4.02: virtual size / auto scrollbars et al.
7 // Created: 01/02/97
8 // RCS-ID: $Id: scrlwing.cpp 55010 2008-08-07 15:58:51Z JS $
9 // Copyright: (c) wxWidgets team
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 // ============================================================================
14 // declarations
15 // ============================================================================
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 #include "wx/scrolwin.h"
29
30 #ifndef WX_PRECOMP
31 #include "wx/utils.h"
32 #include "wx/panel.h"
33 #include "wx/dcclient.h"
34 #if wxUSE_TIMER
35 #include "wx/timer.h"
36 #endif
37 #include "wx/sizer.h"
38 #include "wx/settings.h"
39 #endif
40
41 #ifdef __WXMAC__
42 #include "wx/scrolbar.h"
43 #endif
44
45 #include "wx/recguard.h"
46
47 #ifdef __WXMSW__
48 #include <windows.h> // for DLGC_WANTARROWS
49 #include "wx/msw/winundef.h"
50 #endif
51
52 #ifdef __WXMOTIF__
53 // For wxRETAINED implementation
54 #ifdef __VMS__ //VMS's Xm.h is not (yet) compatible with C++
55 //This code switches off the compiler warnings
56 # pragma message disable nosimpint
57 #endif
58 #include <Xm/Xm.h>
59 #ifdef __VMS__
60 # pragma message enable nosimpint
61 #endif
62 #endif
63
64 /*
65 TODO PROPERTIES
66 style wxHSCROLL | wxVSCROLL
67 */
68
69 // ----------------------------------------------------------------------------
70 // wxScrollHelperEvtHandler: intercept the events from the window and forward
71 // them to wxScrollHelper
72 // ----------------------------------------------------------------------------
73
74 class WXDLLEXPORT wxScrollHelperEvtHandler : public wxEvtHandler
75 {
76 public:
77 wxScrollHelperEvtHandler(wxScrollHelper *scrollHelper)
78 {
79 m_scrollHelper = scrollHelper;
80 }
81
82 virtual bool ProcessEvent(wxEvent& event);
83
84 void ResetDrawnFlag() { m_hasDrawnWindow = false; }
85
86 private:
87 wxScrollHelper *m_scrollHelper;
88
89 bool m_hasDrawnWindow;
90
91 DECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler)
92 };
93
94 #if wxUSE_TIMER
95 // ----------------------------------------------------------------------------
96 // wxAutoScrollTimer: the timer used to generate a stream of scroll events when
97 // a captured mouse is held outside the window
98 // ----------------------------------------------------------------------------
99
100 class wxAutoScrollTimer : public wxTimer
101 {
102 public:
103 wxAutoScrollTimer(wxWindow *winToScroll, wxScrollHelper *scroll,
104 wxEventType eventTypeToSend,
105 int pos, int orient);
106
107 virtual void Notify();
108
109 private:
110 wxWindow *m_win;
111 wxScrollHelper *m_scrollHelper;
112 wxEventType m_eventType;
113 int m_pos,
114 m_orient;
115
116 DECLARE_NO_COPY_CLASS(wxAutoScrollTimer)
117 };
118
119 // ============================================================================
120 // implementation
121 // ============================================================================
122
123 // ----------------------------------------------------------------------------
124 // wxAutoScrollTimer
125 // ----------------------------------------------------------------------------
126
127 wxAutoScrollTimer::wxAutoScrollTimer(wxWindow *winToScroll,
128 wxScrollHelper *scroll,
129 wxEventType eventTypeToSend,
130 int pos, int orient)
131 {
132 m_win = winToScroll;
133 m_scrollHelper = scroll;
134 m_eventType = eventTypeToSend;
135 m_pos = pos;
136 m_orient = orient;
137 }
138
139 void wxAutoScrollTimer::Notify()
140 {
141 // only do all this as long as the window is capturing the mouse
142 if ( wxWindow::GetCapture() != m_win )
143 {
144 Stop();
145 }
146 else // we still capture the mouse, continue generating events
147 {
148 // first scroll the window if we are allowed to do it
149 wxScrollWinEvent event1(m_eventType, m_pos, m_orient);
150 event1.SetEventObject(m_win);
151 if ( m_scrollHelper->SendAutoScrollEvents(event1) &&
152 m_win->GetEventHandler()->ProcessEvent(event1) )
153 {
154 // and then send a pseudo mouse-move event to refresh the selection
155 wxMouseEvent event2(wxEVT_MOTION);
156 wxGetMousePosition(&event2.m_x, &event2.m_y);
157
158 // the mouse event coordinates should be client, not screen as
159 // returned by wxGetMousePosition
160 wxWindow *parentTop = m_win;
161 while ( parentTop->GetParent() )
162 parentTop = parentTop->GetParent();
163 wxPoint ptOrig = parentTop->GetPosition();
164 event2.m_x -= ptOrig.x;
165 event2.m_y -= ptOrig.y;
166
167 event2.SetEventObject(m_win);
168
169 // FIXME: we don't fill in the other members - ok?
170
171 m_win->GetEventHandler()->ProcessEvent(event2);
172 }
173 else // can't scroll further, stop
174 {
175 Stop();
176 }
177 }
178 }
179 #endif
180
181 // ----------------------------------------------------------------------------
182 // wxScrollHelperEvtHandler
183 // ----------------------------------------------------------------------------
184
185 bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
186 {
187 wxEventType evType = event.GetEventType();
188
189 // the explanation of wxEVT_PAINT processing hack: for historic reasons
190 // there are 2 ways to process this event in classes deriving from
191 // wxScrolledWindow. The user code may
192 //
193 // 1. override wxScrolledWindow::OnDraw(dc)
194 // 2. define its own OnPaint() handler
195 //
196 // In addition, in wxUniversal wxWindow defines OnPaint() itself and
197 // always processes the draw event, so we can't just try the window
198 // OnPaint() first and call our HandleOnPaint() if it doesn't process it
199 // (the latter would never be called in wxUniversal).
200 //
201 // So the solution is to have a flag telling us whether the user code drew
202 // anything in the window. We set it to true here but reset it to false in
203 // wxScrolledWindow::OnPaint() handler (which wouldn't be called if the
204 // user code defined OnPaint() in the derived class)
205 m_hasDrawnWindow = true;
206
207 // pass it on to the real handler
208 bool processed = wxEvtHandler::ProcessEvent(event);
209
210 // always process the size events ourselves, even if the user code handles
211 // them as well, as we need to AdjustScrollbars()
212 //
213 // NB: it is important to do it after processing the event in the normal
214 // way as HandleOnSize() may generate a wxEVT_SIZE itself if the
215 // scrollbar[s] (dis)appear and it should be seen by the user code
216 // after this one
217 if ( evType == wxEVT_SIZE )
218 {
219 m_scrollHelper->HandleOnSize((wxSizeEvent &)event);
220
221 return true;
222 }
223
224 if ( processed )
225 {
226 // normally, nothing more to do here - except if it was a paint event
227 // which wasn't really processed, then we'll try to call our
228 // OnDraw() below (from HandleOnPaint)
229 if ( m_hasDrawnWindow || event.IsCommandEvent() )
230 {
231 return true;
232 }
233 }
234
235 // reset the skipped flag to false as it might have been set to true in
236 // ProcessEvent() above
237 event.Skip(false);
238
239 if ( evType == wxEVT_PAINT )
240 {
241 m_scrollHelper->HandleOnPaint((wxPaintEvent &)event);
242 return true;
243 }
244
245 if ( evType == wxEVT_CHILD_FOCUS )
246 {
247 m_scrollHelper->HandleOnChildFocus((wxChildFocusEvent &)event);
248 return true;
249 }
250
251 if ( evType == wxEVT_SCROLLWIN_TOP ||
252 evType == wxEVT_SCROLLWIN_BOTTOM ||
253 evType == wxEVT_SCROLLWIN_LINEUP ||
254 evType == wxEVT_SCROLLWIN_LINEDOWN ||
255 evType == wxEVT_SCROLLWIN_PAGEUP ||
256 evType == wxEVT_SCROLLWIN_PAGEDOWN ||
257 evType == wxEVT_SCROLLWIN_THUMBTRACK ||
258 evType == wxEVT_SCROLLWIN_THUMBRELEASE )
259 {
260 m_scrollHelper->HandleOnScroll((wxScrollWinEvent &)event);
261 return !event.GetSkipped();
262 }
263
264 if ( evType == wxEVT_ENTER_WINDOW )
265 {
266 m_scrollHelper->HandleOnMouseEnter((wxMouseEvent &)event);
267 }
268 else if ( evType == wxEVT_LEAVE_WINDOW )
269 {
270 m_scrollHelper->HandleOnMouseLeave((wxMouseEvent &)event);
271 }
272 #if wxUSE_MOUSEWHEEL
273 else if ( evType == wxEVT_MOUSEWHEEL )
274 {
275 m_scrollHelper->HandleOnMouseWheel((wxMouseEvent &)event);
276 return true;
277 }
278 #endif // wxUSE_MOUSEWHEEL
279 else if ( evType == wxEVT_CHAR )
280 {
281 m_scrollHelper->HandleOnChar((wxKeyEvent &)event);
282 return !event.GetSkipped();
283 }
284
285 return false;
286 }
287
288 // ----------------------------------------------------------------------------
289 // wxScrollHelper construction
290 // ----------------------------------------------------------------------------
291
292 wxScrollHelper::wxScrollHelper(wxWindow *win)
293 {
294 wxASSERT_MSG( win, _T("associated window can't be NULL in wxScrollHelper") );
295
296 m_xScrollPixelsPerLine =
297 m_yScrollPixelsPerLine =
298 m_xScrollPosition =
299 m_yScrollPosition =
300 m_xScrollLines =
301 m_yScrollLines =
302 m_xScrollLinesPerPage =
303 m_yScrollLinesPerPage = 0;
304
305 m_xScrollingEnabled =
306 m_yScrollingEnabled = true;
307
308 m_scaleX =
309 m_scaleY = 1.0;
310 #if wxUSE_MOUSEWHEEL
311 m_wheelRotation = 0;
312 #endif
313
314 m_win =
315 m_targetWindow = (wxWindow *)NULL;
316
317 m_timerAutoScroll = (wxTimer *)NULL;
318
319 m_handler = NULL;
320
321 m_win = win;
322
323 m_win->SetScrollHelper( this );
324
325 // by default, the associated window is also the target window
326 DoSetTargetWindow(win);
327 }
328
329 wxScrollHelper::~wxScrollHelper()
330 {
331 StopAutoScrolling();
332
333 DeleteEvtHandler();
334 }
335
336 // ----------------------------------------------------------------------------
337 // setting scrolling parameters
338 // ----------------------------------------------------------------------------
339
340 void wxScrollHelper::SetScrollbars(int pixelsPerUnitX,
341 int pixelsPerUnitY,
342 int noUnitsX,
343 int noUnitsY,
344 int xPos,
345 int yPos,
346 bool noRefresh)
347 {
348 int xpos, ypos;
349
350 CalcUnscrolledPosition(xPos, yPos, &xpos, &ypos);
351 bool do_refresh =
352 (
353 (noUnitsX != 0 && m_xScrollLines == 0) ||
354 (noUnitsX < m_xScrollLines && xpos > pixelsPerUnitX * noUnitsX) ||
355
356 (noUnitsY != 0 && m_yScrollLines == 0) ||
357 (noUnitsY < m_yScrollLines && ypos > pixelsPerUnitY * noUnitsY) ||
358 (xPos != m_xScrollPosition) ||
359 (yPos != m_yScrollPosition)
360 );
361
362 m_xScrollPixelsPerLine = pixelsPerUnitX;
363 m_yScrollPixelsPerLine = pixelsPerUnitY;
364 m_xScrollPosition = xPos;
365 m_yScrollPosition = yPos;
366
367 int w = noUnitsX * pixelsPerUnitX;
368 int h = noUnitsY * pixelsPerUnitY;
369
370 // For better backward compatibility we set persisting limits
371 // here not just the size. It makes SetScrollbars 'sticky'
372 // emulating the old non-autoscroll behaviour.
373 // m_targetWindow->SetVirtualSizeHints( w, h );
374
375 // The above should arguably be deprecated, this however we still need.
376
377 // take care not to set 0 virtual size, 0 means that we don't have any
378 // scrollbars and hence we should use the real size instead of the virtual
379 // one which is indicated by using wxDefaultCoord
380 m_targetWindow->SetVirtualSize( w ? w : wxDefaultCoord,
381 h ? h : wxDefaultCoord);
382
383 if (do_refresh && !noRefresh)
384 m_targetWindow->Refresh(true, GetScrollRect());
385
386 #ifndef __WXUNIVERSAL__
387 // If the target is not the same as the window with the scrollbars,
388 // then we need to update the scrollbars here, since they won't have
389 // been updated by SetVirtualSize().
390 if ( m_targetWindow != m_win )
391 #endif // !__WXUNIVERSAL__
392 {
393 AdjustScrollbars();
394 }
395 #ifndef __WXUNIVERSAL__
396 else
397 {
398 // otherwise this has been done by AdjustScrollbars, above
399 }
400 #endif // !__WXUNIVERSAL__
401 }
402
403 // ----------------------------------------------------------------------------
404 // [target] window handling
405 // ----------------------------------------------------------------------------
406
407 void wxScrollHelper::DeleteEvtHandler()
408 {
409 // search for m_handler in the handler list
410 if ( m_win && m_handler )
411 {
412 if ( m_win->RemoveEventHandler(m_handler) )
413 {
414 delete m_handler;
415 }
416 //else: something is very wrong, so better [maybe] leak memory than
417 // risk a crash because of double deletion
418
419 m_handler = NULL;
420 }
421 }
422
423 void wxScrollHelper::DoSetTargetWindow(wxWindow *target)
424 {
425 m_targetWindow = target;
426 #ifdef __WXMAC__
427 target->MacSetClipChildren( true ) ;
428 #endif
429
430 // install the event handler which will intercept the events we're
431 // interested in (but only do it for our real window, not the target window
432 // which we scroll - we don't need to hijack its events)
433 if ( m_targetWindow == m_win )
434 {
435 // if we already have a handler, delete it first
436 DeleteEvtHandler();
437
438 m_handler = new wxScrollHelperEvtHandler(this);
439 m_targetWindow->PushEventHandler(m_handler);
440 }
441 }
442
443 void wxScrollHelper::SetTargetWindow(wxWindow *target)
444 {
445 wxCHECK_RET( target, wxT("target window must not be NULL") );
446
447 if ( target == m_targetWindow )
448 return;
449
450 DoSetTargetWindow(target);
451 }
452
453 wxWindow *wxScrollHelper::GetTargetWindow() const
454 {
455 return m_targetWindow;
456 }
457
458 // ----------------------------------------------------------------------------
459 // scrolling implementation itself
460 // ----------------------------------------------------------------------------
461
462 void wxScrollHelper::HandleOnScroll(wxScrollWinEvent& event)
463 {
464 int nScrollInc = CalcScrollInc(event);
465 if ( nScrollInc == 0 )
466 {
467 // can't scroll further
468 event.Skip();
469
470 return;
471 }
472
473 bool needsRefresh = false;
474
475 int dx = 0,
476 dy = 0;
477 int orient = event.GetOrientation();
478 if (orient == wxHORIZONTAL)
479 {
480 if ( m_xScrollingEnabled )
481 {
482 dx = -m_xScrollPixelsPerLine * nScrollInc;
483 }
484 else
485 {
486 needsRefresh = true;
487 }
488 }
489 else
490 {
491 if ( m_yScrollingEnabled )
492 {
493 dy = -m_yScrollPixelsPerLine * nScrollInc;
494 }
495 else
496 {
497 needsRefresh = true;
498 }
499 }
500
501 if ( !needsRefresh )
502 {
503 // flush all pending repaints before we change m_{x,y}ScrollPosition, as
504 // otherwise invalidated area could be updated incorrectly later when
505 // ScrollWindow() makes sure they're repainted before scrolling them
506 #ifdef __WXMAC__
507 // wxWindowMac is taking care of making sure the update area is correctly
508 // set up, while not forcing an immediate redraw
509 #else
510 m_targetWindow->Update();
511 #endif
512 }
513
514 if (orient == wxHORIZONTAL)
515 {
516 m_xScrollPosition += nScrollInc;
517 m_win->SetScrollPos(wxHORIZONTAL, m_xScrollPosition);
518 }
519 else
520 {
521 m_yScrollPosition += nScrollInc;
522 m_win->SetScrollPos(wxVERTICAL, m_yScrollPosition);
523 }
524
525 if ( needsRefresh )
526 {
527 m_targetWindow->Refresh(true, GetScrollRect());
528 }
529 else
530 {
531 m_targetWindow->ScrollWindow(dx, dy, GetScrollRect());
532 }
533 }
534
535 int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event)
536 {
537 int pos = event.GetPosition();
538 int orient = event.GetOrientation();
539
540 int nScrollInc = 0;
541 if (event.GetEventType() == wxEVT_SCROLLWIN_TOP)
542 {
543 if (orient == wxHORIZONTAL)
544 nScrollInc = - m_xScrollPosition;
545 else
546 nScrollInc = - m_yScrollPosition;
547 } else
548 if (event.GetEventType() == wxEVT_SCROLLWIN_BOTTOM)
549 {
550 if (orient == wxHORIZONTAL)
551 nScrollInc = m_xScrollLines - m_xScrollPosition;
552 else
553 nScrollInc = m_yScrollLines - m_yScrollPosition;
554 } else
555 if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP)
556 {
557 nScrollInc = -1;
558 } else
559 if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN)
560 {
561 nScrollInc = 1;
562 } else
563 if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEUP)
564 {
565 if (orient == wxHORIZONTAL)
566 nScrollInc = -GetScrollPageSize(wxHORIZONTAL);
567 else
568 nScrollInc = -GetScrollPageSize(wxVERTICAL);
569 } else
570 if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEDOWN)
571 {
572 if (orient == wxHORIZONTAL)
573 nScrollInc = GetScrollPageSize(wxHORIZONTAL);
574 else
575 nScrollInc = GetScrollPageSize(wxVERTICAL);
576 } else
577 if ((event.GetEventType() == wxEVT_SCROLLWIN_THUMBTRACK) ||
578 (event.GetEventType() == wxEVT_SCROLLWIN_THUMBRELEASE))
579 {
580 if (orient == wxHORIZONTAL)
581 nScrollInc = pos - m_xScrollPosition;
582 else
583 nScrollInc = pos - m_yScrollPosition;
584 }
585
586 if (orient == wxHORIZONTAL)
587 {
588 if (m_xScrollPixelsPerLine > 0)
589 {
590 if ( m_xScrollPosition + nScrollInc < 0 )
591 {
592 // As -ve as we can go
593 nScrollInc = -m_xScrollPosition;
594 }
595 else // check for the other bound
596 {
597 const int posMax = m_xScrollLines - m_xScrollLinesPerPage;
598 if ( m_xScrollPosition + nScrollInc > posMax )
599 {
600 // As +ve as we can go
601 nScrollInc = posMax - m_xScrollPosition;
602 }
603 }
604 }
605 else
606 m_targetWindow->Refresh(true, GetScrollRect());
607 }
608 else
609 {
610 if ( m_yScrollPixelsPerLine > 0 )
611 {
612 if ( m_yScrollPosition + nScrollInc < 0 )
613 {
614 // As -ve as we can go
615 nScrollInc = -m_yScrollPosition;
616 }
617 else // check for the other bound
618 {
619 const int posMax = m_yScrollLines - m_yScrollLinesPerPage;
620 if ( m_yScrollPosition + nScrollInc > posMax )
621 {
622 // As +ve as we can go
623 nScrollInc = posMax - m_yScrollPosition;
624 }
625 }
626 }
627 else
628 {
629 // VZ: why do we do this? (FIXME)
630 m_targetWindow->Refresh(true, GetScrollRect());
631 }
632 }
633
634 return nScrollInc;
635 }
636
637 // Adjust the scrollbars - new version.
638 void wxScrollHelper::AdjustScrollbars()
639 {
640 static wxRecursionGuardFlag s_flagReentrancy;
641 wxRecursionGuard guard(s_flagReentrancy);
642 if ( guard.IsInside() )
643 {
644 // don't reenter AdjustScrollbars() while another call to
645 // AdjustScrollbars() is in progress because this may lead to calling
646 // ScrollWindow() twice and this can really happen under MSW if
647 // SetScrollbar() call below adds or removes the scrollbar which
648 // changes the window size and hence results in another
649 // AdjustScrollbars() call
650 return;
651 }
652
653 int w = 0, h = 0;
654 int oldw, oldh;
655
656 int oldXScroll = m_xScrollPosition;
657 int oldYScroll = m_yScrollPosition;
658
659 // VZ: at least under Windows this loop is useless because when scrollbars
660 // [dis]appear we get a WM_SIZE resulting in another call to
661 // AdjustScrollbars() anyhow. As it doesn't seem to do any harm I leave
662 // it here for now but it would be better to ensure that all ports
663 // generate EVT_SIZE when scrollbars [dis]appear, emulating it if
664 // necessary, and remove it later
665 // JACS: Stop potential infinite loop by limiting number of iterations
666 int iterationCount = 0;
667 const int iterationMax = 5;
668 do
669 {
670 iterationCount ++;
671
672 GetTargetSize(&w, 0);
673
674 // scroll lines per page: if 0, no scrolling is needed
675 int linesPerPage;
676
677 if ( m_xScrollPixelsPerLine == 0 )
678 {
679 // scrolling is disabled
680 m_xScrollLines = 0;
681 m_xScrollPosition = 0;
682 linesPerPage = 0;
683 }
684 else // might need scrolling
685 {
686 // Round up integer division to catch any "leftover" client space.
687 const int wVirt = m_targetWindow->GetVirtualSize().GetWidth();
688 m_xScrollLines = (wVirt + m_xScrollPixelsPerLine - 1) / m_xScrollPixelsPerLine;
689
690 // Calculate page size i.e. number of scroll units you get on the
691 // current client window.
692 linesPerPage = w / m_xScrollPixelsPerLine;
693
694 // Special case. When client and virtual size are very close but
695 // the client is big enough, kill scrollbar.
696 if ((linesPerPage < m_xScrollLines) && (w >= wVirt)) ++linesPerPage;
697
698 if (linesPerPage >= m_xScrollLines)
699 {
700 // we're big enough to not need scrolling
701 linesPerPage =
702 m_xScrollLines =
703 m_xScrollPosition = 0;
704 }
705 else // we do need a scrollbar
706 {
707 if ( linesPerPage < 1 )
708 linesPerPage = 1;
709
710 // Correct position if greater than extent of canvas minus
711 // the visible portion of it or if below zero
712 const int posMax = m_xScrollLines - linesPerPage;
713 if ( m_xScrollPosition > posMax )
714 m_xScrollPosition = posMax;
715 else if ( m_xScrollPosition < 0 )
716 m_xScrollPosition = 0;
717 }
718 }
719
720 m_win->SetScrollbar(wxHORIZONTAL, m_xScrollPosition,
721 linesPerPage, m_xScrollLines);
722
723 // The amount by which we scroll when paging
724 SetScrollPageSize(wxHORIZONTAL, linesPerPage);
725
726 GetTargetSize(0, &h);
727
728 if ( m_yScrollPixelsPerLine == 0 )
729 {
730 // scrolling is disabled
731 m_yScrollLines = 0;
732 m_yScrollPosition = 0;
733 linesPerPage = 0;
734 }
735 else // might need scrolling
736 {
737 // Round up integer division to catch any "leftover" client space.
738 const int hVirt = m_targetWindow->GetVirtualSize().GetHeight();
739 m_yScrollLines = ( hVirt + m_yScrollPixelsPerLine - 1 ) / m_yScrollPixelsPerLine;
740
741 // Calculate page size i.e. number of scroll units you get on the
742 // current client window.
743 linesPerPage = h / m_yScrollPixelsPerLine;
744
745 // Special case. When client and virtual size are very close but
746 // the client is big enough, kill scrollbar.
747 if ((linesPerPage < m_yScrollLines) && (h >= hVirt)) ++linesPerPage;
748
749 if (linesPerPage >= m_yScrollLines)
750 {
751 // we're big enough to not need scrolling
752 linesPerPage =
753 m_yScrollLines =
754 m_yScrollPosition = 0;
755 }
756 else // we do need a scrollbar
757 {
758 if ( linesPerPage < 1 )
759 linesPerPage = 1;
760
761 // Correct position if greater than extent of canvas minus
762 // the visible portion of it or if below zero
763 const int posMax = m_yScrollLines - linesPerPage;
764 if ( m_yScrollPosition > posMax )
765 m_yScrollPosition = posMax;
766 else if ( m_yScrollPosition < 0 )
767 m_yScrollPosition = 0;
768 }
769 }
770
771 m_win->SetScrollbar(wxVERTICAL, m_yScrollPosition,
772 linesPerPage, m_yScrollLines);
773
774 // The amount by which we scroll when paging
775 SetScrollPageSize(wxVERTICAL, linesPerPage);
776
777
778 // If a scrollbar (dis)appeared as a result of this, adjust them again.
779 oldw = w;
780 oldh = h;
781
782 GetTargetSize( &w, &h );
783 } while ( (w != oldw || h != oldh) && (iterationCount < iterationMax) );
784
785 #ifdef __WXMOTIF__
786 // Sorry, some Motif-specific code to implement a backing pixmap
787 // for the wxRETAINED style. Implementing a backing store can't
788 // be entirely generic because it relies on the wxWindowDC implementation
789 // to duplicate X drawing calls for the backing pixmap.
790
791 if ( m_targetWindow->GetWindowStyle() & wxRETAINED )
792 {
793 Display* dpy = XtDisplay((Widget)m_targetWindow->GetMainWidget());
794
795 int totalPixelWidth = m_xScrollLines * m_xScrollPixelsPerLine;
796 int totalPixelHeight = m_yScrollLines * m_yScrollPixelsPerLine;
797 if (m_targetWindow->GetBackingPixmap() &&
798 !((m_targetWindow->GetPixmapWidth() == totalPixelWidth) &&
799 (m_targetWindow->GetPixmapHeight() == totalPixelHeight)))
800 {
801 XFreePixmap (dpy, (Pixmap) m_targetWindow->GetBackingPixmap());
802 m_targetWindow->SetBackingPixmap((WXPixmap) 0);
803 }
804
805 if (!m_targetWindow->GetBackingPixmap() &&
806 (m_xScrollLines != 0) && (m_yScrollLines != 0))
807 {
808 int depth = wxDisplayDepth();
809 m_targetWindow->SetPixmapWidth(totalPixelWidth);
810 m_targetWindow->SetPixmapHeight(totalPixelHeight);
811 m_targetWindow->SetBackingPixmap((WXPixmap) XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
812 m_targetWindow->GetPixmapWidth(), m_targetWindow->GetPixmapHeight(), depth));
813 }
814
815 }
816 #endif // Motif
817
818 if (oldXScroll != m_xScrollPosition)
819 {
820 if (m_xScrollingEnabled)
821 m_targetWindow->ScrollWindow( m_xScrollPixelsPerLine * (oldXScroll - m_xScrollPosition), 0,
822 GetScrollRect() );
823 else
824 m_targetWindow->Refresh(true, GetScrollRect());
825 }
826
827 if (oldYScroll != m_yScrollPosition)
828 {
829 if (m_yScrollingEnabled)
830 m_targetWindow->ScrollWindow( 0, m_yScrollPixelsPerLine * (oldYScroll-m_yScrollPosition),
831 GetScrollRect() );
832 else
833 m_targetWindow->Refresh(true, GetScrollRect());
834 }
835 }
836
837 void wxScrollHelper::DoPrepareDC(wxDC& dc)
838 {
839 wxPoint pt = dc.GetDeviceOrigin();
840 #ifdef __WXGTK__
841 // It may actually be correct to always query
842 // the m_sign from the DC here, but I leve the
843 // #ifdef GTK for now.
844 if (m_win->GetLayoutDirection() == wxLayout_RightToLeft)
845 dc.SetDeviceOrigin( pt.x + m_xScrollPosition * m_xScrollPixelsPerLine,
846 pt.y - m_yScrollPosition * m_yScrollPixelsPerLine );
847 else
848 #endif
849 dc.SetDeviceOrigin( pt.x - m_xScrollPosition * m_xScrollPixelsPerLine,
850 pt.y - m_yScrollPosition * m_yScrollPixelsPerLine );
851 dc.SetUserScale( m_scaleX, m_scaleY );
852 }
853
854 void wxScrollHelper::SetScrollRate( int xstep, int ystep )
855 {
856 int old_x = m_xScrollPixelsPerLine * m_xScrollPosition;
857 int old_y = m_yScrollPixelsPerLine * m_yScrollPosition;
858
859 m_xScrollPixelsPerLine = xstep;
860 m_yScrollPixelsPerLine = ystep;
861
862 int new_x = m_xScrollPixelsPerLine * m_xScrollPosition;
863 int new_y = m_yScrollPixelsPerLine * m_yScrollPosition;
864
865 m_win->SetScrollPos( wxHORIZONTAL, m_xScrollPosition );
866 m_win->SetScrollPos( wxVERTICAL, m_yScrollPosition );
867 m_targetWindow->ScrollWindow( old_x - new_x, old_y - new_y );
868
869 AdjustScrollbars();
870 }
871
872 void wxScrollHelper::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const
873 {
874 if ( x_unit )
875 *x_unit = m_xScrollPixelsPerLine;
876 if ( y_unit )
877 *y_unit = m_yScrollPixelsPerLine;
878 }
879
880
881 int wxScrollHelper::GetScrollLines( int orient ) const
882 {
883 if ( orient == wxHORIZONTAL )
884 return m_xScrollLines;
885 else
886 return m_yScrollLines;
887 }
888
889 int wxScrollHelper::GetScrollPageSize(int orient) const
890 {
891 if ( orient == wxHORIZONTAL )
892 return m_xScrollLinesPerPage;
893 else
894 return m_yScrollLinesPerPage;
895 }
896
897 void wxScrollHelper::SetScrollPageSize(int orient, int pageSize)
898 {
899 if ( orient == wxHORIZONTAL )
900 m_xScrollLinesPerPage = pageSize;
901 else
902 m_yScrollLinesPerPage = pageSize;
903 }
904
905 /*
906 * Scroll to given position (scroll position, not pixel position)
907 */
908 void wxScrollHelper::Scroll( int x_pos, int y_pos )
909 {
910 if (!m_targetWindow)
911 return;
912
913 if (((x_pos == -1) || (x_pos == m_xScrollPosition)) &&
914 ((y_pos == -1) || (y_pos == m_yScrollPosition))) return;
915
916 int w = 0, h = 0;
917 GetTargetSize(&w, &h);
918
919 // compute new position:
920 int new_x = m_xScrollPosition;
921 int new_y = m_yScrollPosition;
922
923 if ((x_pos != -1) && (m_xScrollPixelsPerLine))
924 {
925 new_x = x_pos;
926
927 // Calculate page size i.e. number of scroll units you get on the
928 // current client window
929 int noPagePositions = w/m_xScrollPixelsPerLine;
930 if (noPagePositions < 1) noPagePositions = 1;
931
932 // Correct position if greater than extent of canvas minus
933 // the visible portion of it or if below zero
934 new_x = wxMin( m_xScrollLines-noPagePositions, new_x );
935 new_x = wxMax( 0, new_x );
936 }
937 if ((y_pos != -1) && (m_yScrollPixelsPerLine))
938 {
939 new_y = y_pos;
940
941 // Calculate page size i.e. number of scroll units you get on the
942 // current client window
943 int noPagePositions = h/m_yScrollPixelsPerLine;
944 if (noPagePositions < 1) noPagePositions = 1;
945
946 // Correct position if greater than extent of canvas minus
947 // the visible portion of it or if below zero
948 new_y = wxMin( m_yScrollLines-noPagePositions, new_y );
949 new_y = wxMax( 0, new_y );
950 }
951
952 if ( new_x == m_xScrollPosition && new_y == m_yScrollPosition )
953 return; // nothing to do, the position didn't change
954
955 // flush all pending repaints before we change m_{x,y}ScrollPosition, as
956 // otherwise invalidated area could be updated incorrectly later when
957 // ScrollWindow() makes sure they're repainted before scrolling them
958 m_targetWindow->Update();
959
960 // update the position and scroll the window now:
961 if (m_xScrollPosition != new_x)
962 {
963 int old_x = m_xScrollPosition;
964 m_xScrollPosition = new_x;
965 m_win->SetScrollPos( wxHORIZONTAL, new_x );
966 m_targetWindow->ScrollWindow( (old_x-new_x)*m_xScrollPixelsPerLine, 0,
967 GetScrollRect() );
968 }
969
970 if (m_yScrollPosition != new_y)
971 {
972 int old_y = m_yScrollPosition;
973 m_yScrollPosition = new_y;
974 m_win->SetScrollPos( wxVERTICAL, new_y );
975 m_targetWindow->ScrollWindow( 0, (old_y-new_y)*m_yScrollPixelsPerLine,
976 GetScrollRect() );
977 }
978 }
979
980 void wxScrollHelper::EnableScrolling (bool x_scroll, bool y_scroll)
981 {
982 m_xScrollingEnabled = x_scroll;
983 m_yScrollingEnabled = y_scroll;
984 }
985
986 // Where the current view starts from
987 void wxScrollHelper::GetViewStart (int *x, int *y) const
988 {
989 if ( x )
990 *x = m_xScrollPosition;
991 if ( y )
992 *y = m_yScrollPosition;
993 }
994
995 void wxScrollHelper::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) const
996 {
997 if ( xx )
998 *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
999 if ( yy )
1000 *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine;
1001 }
1002
1003 void wxScrollHelper::DoCalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
1004 {
1005 if ( xx )
1006 *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine;
1007 if ( yy )
1008 *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine;
1009 }
1010
1011 // ----------------------------------------------------------------------------
1012 // geometry
1013 // ----------------------------------------------------------------------------
1014
1015 bool wxScrollHelper::ScrollLayout()
1016 {
1017 if ( m_win->GetSizer() && m_targetWindow == m_win )
1018 {
1019 // If we're the scroll target, take into account the
1020 // virtual size and scrolled position of the window.
1021
1022 int x = 0, y = 0, w = 0, h = 0;
1023 CalcScrolledPosition(0,0, &x,&y);
1024 m_win->GetVirtualSize(&w, &h);
1025 m_win->GetSizer()->SetDimension(x, y, w, h);
1026 return true;
1027 }
1028
1029 // fall back to default for LayoutConstraints
1030 return m_win->wxWindow::Layout();
1031 }
1032
1033 void wxScrollHelper::ScrollDoSetVirtualSize(int x, int y)
1034 {
1035 m_win->wxWindow::DoSetVirtualSize( x, y );
1036 AdjustScrollbars();
1037
1038 if (m_win->GetAutoLayout())
1039 m_win->Layout();
1040 }
1041
1042 // wxWindow's GetBestVirtualSize returns the actual window size,
1043 // whereas we want to return the virtual size
1044 wxSize wxScrollHelper::ScrollGetBestVirtualSize() const
1045 {
1046 wxSize clientSize(m_win->GetClientSize());
1047 if ( m_win->GetSizer() )
1048 clientSize.IncTo(m_win->GetSizer()->CalcMin());
1049
1050 return clientSize;
1051 }
1052
1053 // return the window best size from the given best virtual size
1054 wxSize
1055 wxScrollHelper::ScrollGetWindowSizeForVirtualSize(const wxSize& size) const
1056 {
1057 // Only use the content to set the window size in the direction
1058 // where there's no scrolling; otherwise we're going to get a huge
1059 // window in the direction in which scrolling is enabled
1060 int ppuX, ppuY;
1061 GetScrollPixelsPerUnit(&ppuX, &ppuY);
1062
1063 wxSize minSize = m_win->GetMinSize();
1064
1065 wxSize best(size);
1066 if (ppuX > 0)
1067 best.x = minSize.x + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
1068 if (ppuY > 0)
1069 best.y = minSize.y + wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
1070
1071 return best;
1072 }
1073
1074 // ----------------------------------------------------------------------------
1075 // event handlers
1076 // ----------------------------------------------------------------------------
1077
1078 // Default OnSize resets scrollbars, if any
1079 void wxScrollHelper::HandleOnSize(wxSizeEvent& WXUNUSED(event))
1080 {
1081 if ( m_targetWindow->GetAutoLayout() )
1082 {
1083 wxSize size = m_targetWindow->GetBestVirtualSize();
1084
1085 // This will call ::Layout() and ::AdjustScrollbars()
1086 m_win->SetVirtualSize( size );
1087 }
1088 else
1089 {
1090 AdjustScrollbars();
1091 }
1092 }
1093
1094 // This calls OnDraw, having adjusted the origin according to the current
1095 // scroll position
1096 void wxScrollHelper::HandleOnPaint(wxPaintEvent& WXUNUSED(event))
1097 {
1098 // don't use m_targetWindow here, this is always called for ourselves
1099 wxPaintDC dc(m_win);
1100 DoPrepareDC(dc);
1101
1102 OnDraw(dc);
1103 }
1104
1105 // kbd handling: notice that we use OnChar() and not OnKeyDown() for
1106 // compatibility here - if we used OnKeyDown(), the programs which process
1107 // arrows themselves in their OnChar() would never get the message and like
1108 // this they always have the priority
1109 void wxScrollHelper::HandleOnChar(wxKeyEvent& event)
1110 {
1111 int stx = 0, sty = 0, // view origin
1112 szx = 0, szy = 0, // view size (total)
1113 clix = 0, cliy = 0; // view size (on screen)
1114
1115 GetViewStart(&stx, &sty);
1116 GetTargetSize(&clix, &cliy);
1117 m_targetWindow->GetVirtualSize(&szx, &szy);
1118
1119 if( m_xScrollPixelsPerLine )
1120 {
1121 clix /= m_xScrollPixelsPerLine;
1122 szx /= m_xScrollPixelsPerLine;
1123 }
1124 else
1125 {
1126 clix = 0;
1127 szx = -1;
1128 }
1129 if( m_yScrollPixelsPerLine )
1130 {
1131 cliy /= m_yScrollPixelsPerLine;
1132 szy /= m_yScrollPixelsPerLine;
1133 }
1134 else
1135 {
1136 cliy = 0;
1137 szy = -1;
1138 }
1139
1140 int xScrollOld = m_xScrollPosition,
1141 yScrollOld = m_yScrollPosition;
1142
1143 int dsty;
1144 switch ( event.GetKeyCode() )
1145 {
1146 case WXK_PAGEUP:
1147 dsty = sty - (5 * cliy / 6);
1148 Scroll(-1, (dsty == -1) ? 0 : dsty);
1149 break;
1150
1151 case WXK_PAGEDOWN:
1152 Scroll(-1, sty + (5 * cliy / 6));
1153 break;
1154
1155 case WXK_HOME:
1156 Scroll(0, event.ControlDown() ? 0 : -1);
1157 break;
1158
1159 case WXK_END:
1160 Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1);
1161 break;
1162
1163 case WXK_UP:
1164 Scroll(-1, sty - 1);
1165 break;
1166
1167 case WXK_DOWN:
1168 Scroll(-1, sty + 1);
1169 break;
1170
1171 case WXK_LEFT:
1172 Scroll(stx - 1, -1);
1173 break;
1174
1175 case WXK_RIGHT:
1176 Scroll(stx + 1, -1);
1177 break;
1178
1179 default:
1180 // not for us
1181 event.Skip();
1182 }
1183
1184 if ( m_xScrollPosition != xScrollOld )
1185 {
1186 wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_xScrollPosition,
1187 wxHORIZONTAL);
1188 event.SetEventObject(m_win);
1189 m_win->GetEventHandler()->ProcessEvent(event);
1190 }
1191
1192 if ( m_yScrollPosition != yScrollOld )
1193 {
1194 wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_yScrollPosition,
1195 wxVERTICAL);
1196 event.SetEventObject(m_win);
1197 m_win->GetEventHandler()->ProcessEvent(event);
1198 }
1199 }
1200
1201 // ----------------------------------------------------------------------------
1202 // autoscroll stuff: these functions deal with sending fake scroll events when
1203 // a captured mouse is being held outside the window
1204 // ----------------------------------------------------------------------------
1205
1206 bool wxScrollHelper::SendAutoScrollEvents(wxScrollWinEvent& event) const
1207 {
1208 // only send the event if the window is scrollable in this direction
1209 wxWindow *win = (wxWindow *)event.GetEventObject();
1210 return win->HasScrollbar(event.GetOrientation());
1211 }
1212
1213 void wxScrollHelper::StopAutoScrolling()
1214 {
1215 #if wxUSE_TIMER
1216 if ( m_timerAutoScroll )
1217 {
1218 delete m_timerAutoScroll;
1219 m_timerAutoScroll = (wxTimer *)NULL;
1220 }
1221 #endif
1222 }
1223
1224 void wxScrollHelper::HandleOnMouseEnter(wxMouseEvent& event)
1225 {
1226 StopAutoScrolling();
1227
1228 event.Skip();
1229 }
1230
1231 void wxScrollHelper::HandleOnMouseLeave(wxMouseEvent& event)
1232 {
1233 // don't prevent the usual processing of the event from taking place
1234 event.Skip();
1235
1236 // when a captured mouse leave a scrolled window we start generate
1237 // scrolling events to allow, for example, extending selection beyond the
1238 // visible area in some controls
1239 if ( wxWindow::GetCapture() == m_targetWindow )
1240 {
1241 // where is the mouse leaving?
1242 int pos, orient;
1243 wxPoint pt = event.GetPosition();
1244 if ( pt.x < 0 )
1245 {
1246 orient = wxHORIZONTAL;
1247 pos = 0;
1248 }
1249 else if ( pt.y < 0 )
1250 {
1251 orient = wxVERTICAL;
1252 pos = 0;
1253 }
1254 else // we're lower or to the right of the window
1255 {
1256 wxSize size = m_targetWindow->GetClientSize();
1257 if ( pt.x > size.x )
1258 {
1259 orient = wxHORIZONTAL;
1260 pos = m_xScrollLines;
1261 }
1262 else if ( pt.y > size.y )
1263 {
1264 orient = wxVERTICAL;
1265 pos = m_yScrollLines;
1266 }
1267 else // this should be impossible
1268 {
1269 // but seems to happen sometimes under wxMSW - maybe it's a bug
1270 // there but for now just ignore it
1271
1272 //wxFAIL_MSG( _T("can't understand where has mouse gone") );
1273
1274 return;
1275 }
1276 }
1277
1278 // only start the auto scroll timer if the window can be scrolled in
1279 // this direction
1280 if ( !m_targetWindow->HasScrollbar(orient) )
1281 return;
1282
1283 #if wxUSE_TIMER
1284 delete m_timerAutoScroll;
1285 m_timerAutoScroll = new wxAutoScrollTimer
1286 (
1287 m_targetWindow, this,
1288 pos == 0 ? wxEVT_SCROLLWIN_LINEUP
1289 : wxEVT_SCROLLWIN_LINEDOWN,
1290 pos,
1291 orient
1292 );
1293 m_timerAutoScroll->Start(50); // FIXME: make configurable
1294 #else
1295 wxUnusedVar(pos);
1296 #endif
1297 }
1298 }
1299
1300 #if wxUSE_MOUSEWHEEL
1301
1302 void wxScrollHelper::HandleOnMouseWheel(wxMouseEvent& event)
1303 {
1304 m_wheelRotation += event.GetWheelRotation();
1305 int lines = m_wheelRotation / event.GetWheelDelta();
1306 m_wheelRotation -= lines * event.GetWheelDelta();
1307
1308 if (lines != 0)
1309 {
1310
1311 wxScrollWinEvent newEvent;
1312
1313 newEvent.SetPosition(0);
1314 newEvent.SetOrientation(wxVERTICAL);
1315 newEvent.SetEventObject(m_win);
1316
1317 if (event.IsPageScroll())
1318 {
1319 if (lines > 0)
1320 newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEUP);
1321 else
1322 newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);
1323
1324 m_win->GetEventHandler()->ProcessEvent(newEvent);
1325 }
1326 else
1327 {
1328 lines *= event.GetLinesPerAction();
1329 if (lines > 0)
1330 newEvent.SetEventType(wxEVT_SCROLLWIN_LINEUP);
1331 else
1332 newEvent.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);
1333
1334 int times = abs(lines);
1335 for (; times > 0; times--)
1336 m_win->GetEventHandler()->ProcessEvent(newEvent);
1337 }
1338 }
1339 }
1340
1341 #endif // wxUSE_MOUSEWHEEL
1342
1343 void wxScrollHelper::HandleOnChildFocus(wxChildFocusEvent& event)
1344 {
1345 // this event should be processed by all windows in parenthood chain,
1346 // e.g. so that nested wxScrolledWindows work correctly
1347 event.Skip();
1348
1349 // find the immediate child under which the window receiving focus is:
1350 wxWindow *win = event.GetWindow();
1351
1352 if ( win == m_targetWindow )
1353 return; // nothing to do
1354
1355 #ifdef __WXMAC__
1356 if (wxDynamicCast(win, wxScrollBar))
1357 return;
1358 #endif
1359
1360 // Fixing ticket: http://trac.wxwidgets.org/ticket/9563
1361 // When a child inside a wxControlContainer receives a focus, the
1362 // wxControlContainer generates an artificial wxChildFocusEvent for
1363 // itself, telling its parent that 'it' received the focus. The effect is
1364 // that this->HandleOnChildFocus is called twice, first with the
1365 // artificial wxChildFocusEvent and then with the original event. We need
1366 // to ignore the artificial event here or otherwise HandleOnChildFocus
1367 // would first scroll the target window to make the entire
1368 // wxControlContainer visible and immediately afterwards scroll the target
1369 // window again to make the child widget visible. This leads to ugly
1370 // flickering when using nested wxPanels/wxScrolledWindows.
1371 //
1372 // Ignore this event if 'win' is derived from wxControlContainer AND its
1373 // parent is the m_targetWindow AND 'win' is not actually reciving the
1374 // focus (win != FindFocus). TODO: This affects all wxControlContainer
1375 // objects, but wxControlContainer is not part of the wxWidgets RTTI and
1376 // so wxDynamicCast(win, wxControlContainer) does not compile. Find a way
1377 // to determine if 'win' derives from wxControlContainer. Until then,
1378 // testing if 'win' derives from wxPanel will probably get >90% of all
1379 // cases.
1380
1381 wxWindow *actual_focus=wxWindow::FindFocus();
1382 if (win != actual_focus &&
1383 wxDynamicCast(win, wxPanel) != 0 &&
1384 win->GetParent() == m_targetWindow)
1385 // if win is a wxPanel and receives the focus, it should not be
1386 // scrolled into view
1387 return;
1388
1389 wxSize view(m_targetWindow->GetClientSize());
1390
1391 // For composite controls such as wxComboCtrl we should try to fit the
1392 // entire control inside the visible area of the target window, not just
1393 // the focused child of the control. Otherwise we'd make only the textctrl
1394 // part of a wxComboCtrl visible and the button would still be outside the
1395 // scrolled area. But do so only if the parent fits *entirely* inside the
1396 // scrolled window. In other situations, such as nested wxPanel or
1397 // wxScrolledWindows, the parent might be way to big to fit inside the
1398 // scrolled window. If that is the case, then make only the focused window
1399 // visible
1400 if ( win->GetParent() != m_targetWindow)
1401 {
1402 wxWindow *parent=win->GetParent();
1403 wxSize parent_size=parent->GetSize();
1404 if (parent_size.GetWidth() <= view.GetWidth() &&
1405 parent_size.GetHeight() <= view.GetHeight())
1406 // make the immediate parent visible instead of the focused control
1407 win=parent;
1408 }
1409
1410 // if the child is not fully visible, try to scroll it into view:
1411 int stepx, stepy;
1412 GetScrollPixelsPerUnit(&stepx, &stepy);
1413
1414 // 'win' position coordinates are relative to it's parent
1415 // convert them so that they are relative to the m_targetWindow viewing area
1416 wxRect winrect(m_targetWindow->ScreenToClient(win->GetScreenPosition()),
1417 win->GetSize());
1418
1419 int startx, starty;
1420 GetViewStart(&startx, &starty);
1421
1422 // first in vertical direction:
1423 if ( stepy > 0 )
1424 {
1425 int diff = 0;
1426
1427 if ( winrect.GetTop() < 0 )
1428 {
1429 diff = winrect.GetTop();
1430 }
1431 else if ( winrect.GetBottom() > view.y )
1432 {
1433 diff = winrect.GetBottom() - view.y + 1;
1434 // round up to next scroll step if we can't get exact position,
1435 // so that the window is fully visible:
1436 diff += stepy - 1;
1437 }
1438
1439 starty = (starty * stepy + diff) / stepy;
1440 }
1441
1442 // then horizontal:
1443 if ( stepx > 0 )
1444 {
1445 int diff = 0;
1446
1447 if ( winrect.GetLeft() < 0 )
1448 {
1449 diff = winrect.GetLeft();
1450 }
1451 else if ( winrect.GetRight() > view.x )
1452 {
1453 diff = winrect.GetRight() - view.x + 1;
1454 // round up to next scroll step if we can't get exact position,
1455 // so that the window is fully visible:
1456 diff += stepx - 1;
1457 }
1458
1459 startx = (startx * stepx + diff) / stepx;
1460 }
1461
1462 Scroll(startx, starty);
1463 }
1464
1465 // ----------------------------------------------------------------------------
1466 // wxScrolledWindow implementation
1467 // ----------------------------------------------------------------------------
1468
1469 IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel)
1470
1471 BEGIN_EVENT_TABLE(wxScrolledWindow, wxPanel)
1472 EVT_PAINT(wxScrolledWindow::OnPaint)
1473 END_EVENT_TABLE()
1474
1475 bool wxScrolledWindow::Create(wxWindow *parent,
1476 wxWindowID id,
1477 const wxPoint& pos,
1478 const wxSize& size,
1479 long style,
1480 const wxString& name)
1481 {
1482 m_targetWindow = this;
1483 #ifdef __WXMAC__
1484 MacSetClipChildren( true ) ;
1485 #endif
1486
1487 bool ok = wxPanel::Create(parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1488
1489 return ok;
1490 }
1491
1492 wxScrolledWindow::~wxScrolledWindow()
1493 {
1494 }
1495
1496 void wxScrolledWindow::OnPaint(wxPaintEvent& event)
1497 {
1498 // the user code didn't really draw the window if we got here, so set this
1499 // flag to try to call OnDraw() later
1500 m_handler->ResetDrawnFlag();
1501
1502 event.Skip();
1503 }
1504
1505 #ifdef __WXMSW__
1506 WXLRESULT wxScrolledWindow::MSWWindowProc(WXUINT nMsg,
1507 WXWPARAM wParam,
1508 WXLPARAM lParam)
1509 {
1510 WXLRESULT rc = wxPanel::MSWWindowProc(nMsg, wParam, lParam);
1511
1512 #ifndef __WXWINCE__
1513 // we need to process arrows ourselves for scrolling
1514 if ( nMsg == WM_GETDLGCODE )
1515 {
1516 rc |= DLGC_WANTARROWS;
1517 }
1518 #endif
1519
1520 return rc;
1521 }
1522
1523 #endif // __WXMSW__

  ViewVC Help
Powered by ViewVC 1.1.22