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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (hide annotations) (download)
Tue Sep 7 03:29:01 2010 UTC (10 years 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 william 31 /////////////////////////////////////////////////////////////////////////////
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