2003-11-12 16:34:20 -05:00
|
|
|
#----------------------------------------------------------------------------
|
2003-12-22 14:09:54 -05:00
|
|
|
# Name: scrolledpanel.py
|
2003-11-12 16:34:20 -05:00
|
|
|
# Author: Will Sadkin
|
|
|
|
# Created: 03/21/2003
|
|
|
|
# Copyright: (c) 2003 by Will Sadkin
|
|
|
|
# RCS-ID: $Id$
|
|
|
|
# License: wxWindows license
|
|
|
|
#----------------------------------------------------------------------------
|
2003-12-16 19:34:40 -05:00
|
|
|
# 12/11/2003 - Jeff Grimmett (grimmtooth@softhome.net)
|
|
|
|
#
|
|
|
|
# o 2.5 compatability update.
|
2003-11-12 16:34:20 -05:00
|
|
|
#
|
2003-12-22 14:09:54 -05:00
|
|
|
# 12/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)
|
|
|
|
#
|
|
|
|
# o wxScrolledPanel -> ScrolledPanel
|
|
|
|
#
|
2003-07-02 19:13:10 -04:00
|
|
|
|
2003-12-16 19:34:40 -05:00
|
|
|
import wx
|
2003-07-02 19:13:10 -04:00
|
|
|
|
2003-11-12 16:34:20 -05:00
|
|
|
|
2004-05-28 00:22:16 -04:00
|
|
|
class ScrolledPanel( wx.PyScrolledWindow ):
|
|
|
|
|
|
|
|
""" ScrolledPanel fills a "hole" in the implementation of
|
|
|
|
wx.ScrolledWindow, providing automatic scrollbar and scrolling
|
|
|
|
behavior and the tab traversal management that wxScrolledWindow
|
|
|
|
lacks. This code was based on the original demo code showing how
|
|
|
|
to do this, but is now available for general use as a proper class
|
|
|
|
(and the demo is now converted to just use it.)
|
|
|
|
|
|
|
|
It is assumed that the ScrolledPanel will have a sizer, as it is
|
|
|
|
used to calculate the minimal virtual size of the panel and etc.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, parent, id=-1, pos = wx.DefaultPosition,
|
|
|
|
size = wx.DefaultSize, style = wx.TAB_TRAVERSAL,
|
|
|
|
name = "scrolledpanel"):
|
|
|
|
|
|
|
|
wx.PyScrolledWindow.__init__(self, parent, -1,
|
|
|
|
pos=pos, size=size,
|
|
|
|
style=style, name=name)
|
|
|
|
self.SetBestSize(size)
|
2003-12-16 19:34:40 -05:00
|
|
|
self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus)
|
2003-11-12 16:34:20 -05:00
|
|
|
|
|
|
|
|
|
|
|
def SetupScrolling(self, scroll_x=True, scroll_y=True, rate_x=20, rate_y=20):
|
|
|
|
"""
|
|
|
|
This function sets up the event handling necessary to handle
|
|
|
|
scrolling properly. It should be called within the __init__
|
2003-12-22 14:09:54 -05:00
|
|
|
function of any class that is derived from ScrolledPanel,
|
2003-11-12 16:34:20 -05:00
|
|
|
once the controls on the panel have been constructed and
|
|
|
|
thus the size of the scrolling area can be determined.
|
|
|
|
|
|
|
|
"""
|
|
|
|
# The following is all that is needed to integrate the sizer and the
|
|
|
|
# scrolled window.
|
|
|
|
if not scroll_x: rate_x = 0
|
|
|
|
if not scroll_y: rate_y = 0
|
|
|
|
|
|
|
|
# Round up the virtual size to be a multiple of the scroll rate
|
|
|
|
sizer = self.GetSizer()
|
|
|
|
if sizer:
|
|
|
|
w, h = sizer.GetMinSize()
|
|
|
|
if rate_x:
|
|
|
|
w += rate_x - (w % rate_x)
|
|
|
|
if rate_y:
|
|
|
|
h += rate_y - (h % rate_y)
|
|
|
|
self.SetVirtualSize( (w, h) )
|
|
|
|
self.SetVirtualSizeHints( w, h )
|
|
|
|
|
|
|
|
self.SetScrollRate(rate_x, rate_y)
|
2003-12-16 19:34:40 -05:00
|
|
|
wx.CallAfter(self.Scroll, 0, 0) # scroll back to top after initial events
|
2003-11-12 16:34:20 -05:00
|
|
|
|
|
|
|
|
|
|
|
def OnChildFocus(self, evt):
|
|
|
|
# If the child window that gets the focus is not visible,
|
|
|
|
# this handler will try to scroll enough to see it.
|
|
|
|
evt.Skip()
|
|
|
|
child = evt.GetWindow()
|
|
|
|
|
|
|
|
sppu_x, sppu_y = self.GetScrollPixelsPerUnit()
|
|
|
|
vs_x, vs_y = self.GetViewStart()
|
2004-05-28 00:22:16 -04:00
|
|
|
cr = child.GetRect()
|
|
|
|
clntsz = self.GetClientSize()
|
2003-11-12 16:34:20 -05:00
|
|
|
new_vs_x, new_vs_y = -1, -1
|
|
|
|
|
|
|
|
# is it before the left edge?
|
2004-05-28 00:22:16 -04:00
|
|
|
if cr.x < 0 and sppu_x > 0:
|
|
|
|
new_vs_x = vs_x + (cr.x / sppu_x)
|
2003-11-12 16:34:20 -05:00
|
|
|
|
|
|
|
# is it above the top?
|
2004-05-28 00:22:16 -04:00
|
|
|
if cr.y < 0 and sppu_y > 0:
|
|
|
|
new_vs_y = vs_y + (cr.y / sppu_y)
|
2003-11-12 16:34:20 -05:00
|
|
|
|
|
|
|
|
2004-05-28 00:22:16 -04:00
|
|
|
# For the right and bottom edges, scroll enough to show the
|
|
|
|
# whole control if possible, but if not just scroll such that
|
|
|
|
# the top/left edges are still visible
|
2003-11-12 16:34:20 -05:00
|
|
|
|
2004-05-28 00:22:16 -04:00
|
|
|
# is it past the right edge ?
|
|
|
|
if cr.right > clntsz.width and sppu_x > 0:
|
|
|
|
diff = (cr.right - clntsz.width) / sppu_x
|
|
|
|
if cr.x - diff * sppu_x > 0:
|
|
|
|
new_vs_x = vs_x + diff + 1
|
|
|
|
else:
|
|
|
|
new_vs_x = vs_x + (cr.x / sppu_x)
|
|
|
|
|
2003-11-12 16:34:20 -05:00
|
|
|
# is it below the bottom ?
|
2004-05-28 00:22:16 -04:00
|
|
|
if cr.bottom > clntsz.height and sppu_y > 0:
|
|
|
|
diff = (cr.bottom - clntsz.height) / sppu_y
|
|
|
|
if cr.y - diff * sppu_y > 0:
|
|
|
|
new_vs_y = vs_y + diff + 1
|
|
|
|
else:
|
|
|
|
new_vs_y = vs_y + (cr.y / sppu_y)
|
|
|
|
|
2003-11-12 16:34:20 -05:00
|
|
|
|
|
|
|
# if we need to adjust
|
|
|
|
if new_vs_x != -1 or new_vs_y != -1:
|
2004-05-28 00:22:16 -04:00
|
|
|
#print "%s: (%s, %s)" % (self.GetName(), new_vs_x, new_vs_y)
|
2003-11-12 16:34:20 -05:00
|
|
|
self.Scroll(new_vs_x, new_vs_y)
|