]>
Commit | Line | Data |
---|---|---|
d14a1e28 | 1 | #---------------------------------------------------------------------------- |
d4b73b1b | 2 | # Name: scrolledpanel.py |
d14a1e28 RD |
3 | # Author: Will Sadkin |
4 | # Created: 03/21/2003 | |
5 | # Copyright: (c) 2003 by Will Sadkin | |
6 | # RCS-ID: $Id$ | |
7 | # License: wxWindows license | |
8 | #---------------------------------------------------------------------------- | |
b881fc78 RD |
9 | # 12/11/2003 - Jeff Grimmett (grimmtooth@softhome.net) |
10 | # | |
11 | # o 2.5 compatability update. | |
d14a1e28 | 12 | # |
d4b73b1b RD |
13 | # 12/21/2003 - Jeff Grimmett (grimmtooth@softhome.net) |
14 | # | |
15 | # o wxScrolledPanel -> ScrolledPanel | |
16 | # | |
1fded56b | 17 | |
b881fc78 | 18 | import wx |
1fded56b | 19 | |
d14a1e28 | 20 | |
68c0610d RD |
21 | class ScrolledPanel( wx.PyScrolledWindow ): |
22 | ||
23 | """ ScrolledPanel fills a "hole" in the implementation of | |
24 | wx.ScrolledWindow, providing automatic scrollbar and scrolling | |
25 | behavior and the tab traversal management that wxScrolledWindow | |
26 | lacks. This code was based on the original demo code showing how | |
27 | to do this, but is now available for general use as a proper class | |
28 | (and the demo is now converted to just use it.) | |
29 | ||
30 | It is assumed that the ScrolledPanel will have a sizer, as it is | |
31 | used to calculate the minimal virtual size of the panel and etc. | |
32 | """ | |
33 | ||
34 | def __init__(self, parent, id=-1, pos = wx.DefaultPosition, | |
35 | size = wx.DefaultSize, style = wx.TAB_TRAVERSAL, | |
36 | name = "scrolledpanel"): | |
37 | ||
e345fb0b | 38 | wx.PyScrolledWindow.__init__(self, parent, id, |
68c0610d RD |
39 | pos=pos, size=size, |
40 | style=style, name=name) | |
5193b348 | 41 | self.SetBestFittingSize(size) |
b881fc78 | 42 | self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus) |
d14a1e28 RD |
43 | |
44 | ||
45 | def SetupScrolling(self, scroll_x=True, scroll_y=True, rate_x=20, rate_y=20): | |
46 | """ | |
47 | This function sets up the event handling necessary to handle | |
48 | scrolling properly. It should be called within the __init__ | |
d4b73b1b | 49 | function of any class that is derived from ScrolledPanel, |
d14a1e28 RD |
50 | once the controls on the panel have been constructed and |
51 | thus the size of the scrolling area can be determined. | |
52 | ||
53 | """ | |
54 | # The following is all that is needed to integrate the sizer and the | |
55 | # scrolled window. | |
56 | if not scroll_x: rate_x = 0 | |
57 | if not scroll_y: rate_y = 0 | |
58 | ||
59 | # Round up the virtual size to be a multiple of the scroll rate | |
60 | sizer = self.GetSizer() | |
61 | if sizer: | |
62 | w, h = sizer.GetMinSize() | |
63 | if rate_x: | |
64 | w += rate_x - (w % rate_x) | |
65 | if rate_y: | |
66 | h += rate_y - (h % rate_y) | |
67 | self.SetVirtualSize( (w, h) ) | |
9ce00180 RD |
68 | self.SetScrollRate(rate_x, rate_y) |
69 | wx.CallAfter(self._SetupAfter) # scroll back to top after initial events | |
d14a1e28 | 70 | |
9ce00180 RD |
71 | |
72 | def _SetupAfter(self): | |
73 | self.SetVirtualSize(self.GetBestVirtualSize()) | |
74 | self.Scroll(0,0) | |
d14a1e28 RD |
75 | |
76 | ||
77 | def OnChildFocus(self, evt): | |
78 | # If the child window that gets the focus is not visible, | |
79 | # this handler will try to scroll enough to see it. | |
80 | evt.Skip() | |
81 | child = evt.GetWindow() | |
82 | ||
83 | sppu_x, sppu_y = self.GetScrollPixelsPerUnit() | |
84 | vs_x, vs_y = self.GetViewStart() | |
68c0610d RD |
85 | cr = child.GetRect() |
86 | clntsz = self.GetClientSize() | |
d14a1e28 RD |
87 | new_vs_x, new_vs_y = -1, -1 |
88 | ||
89 | # is it before the left edge? | |
68c0610d RD |
90 | if cr.x < 0 and sppu_x > 0: |
91 | new_vs_x = vs_x + (cr.x / sppu_x) | |
d14a1e28 RD |
92 | |
93 | # is it above the top? | |
68c0610d RD |
94 | if cr.y < 0 and sppu_y > 0: |
95 | new_vs_y = vs_y + (cr.y / sppu_y) | |
d14a1e28 | 96 | |
68c0610d RD |
97 | # For the right and bottom edges, scroll enough to show the |
98 | # whole control if possible, but if not just scroll such that | |
99 | # the top/left edges are still visible | |
d14a1e28 | 100 | |
68c0610d RD |
101 | # is it past the right edge ? |
102 | if cr.right > clntsz.width and sppu_x > 0: | |
103 | diff = (cr.right - clntsz.width) / sppu_x | |
104 | if cr.x - diff * sppu_x > 0: | |
105 | new_vs_x = vs_x + diff + 1 | |
106 | else: | |
107 | new_vs_x = vs_x + (cr.x / sppu_x) | |
108 | ||
d14a1e28 | 109 | # is it below the bottom ? |
68c0610d RD |
110 | if cr.bottom > clntsz.height and sppu_y > 0: |
111 | diff = (cr.bottom - clntsz.height) / sppu_y | |
112 | if cr.y - diff * sppu_y > 0: | |
113 | new_vs_y = vs_y + diff + 1 | |
114 | else: | |
115 | new_vs_y = vs_y + (cr.y / sppu_y) | |
116 | ||
d14a1e28 RD |
117 | # if we need to adjust |
118 | if new_vs_x != -1 or new_vs_y != -1: | |
68c0610d | 119 | #print "%s: (%s, %s)" % (self.GetName(), new_vs_x, new_vs_y) |
d14a1e28 | 120 | self.Scroll(new_vs_x, new_vs_y) |