# $Id: ViewPort.py,v 1.9.2.2 2006/09/14 23:32:01 marcusva Exp $
#
# Copyright (c) 2004-2006, Marcus von Appen
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
"""A proxy class for widgets, that need to be scrolled."""
from pygame import Rect
from Bin import Bin
from BaseWidget import BaseWidget
from StyleInformation import StyleInformation
import base
class ViewPort (Bin):
"""ViewPort (widget) -> ViewPort
A proxy class for widgets, which need scrolling abilities.
The ViewPort class allows widgets to be scrolled by virtually adding
horizontal and vertical offsets to the respective methods such as
rect_to_client().
Widgets which make use of the ViewPort class can easily scroll the
encapsulated child(ren) by modifying the 'hadjustment' and
'vadjustment' attributes of the ViewPort.
viewport.hadjustment = 10 # Add a 10px horizontal offset.
viewport.set_vadjustment (-15) # Reduce by a 15px vertical offset.
The ViewPort however does not provide advanced scrolling features
such as scrollbars. Instead it should be bound as child to a widget,
which will implement such additives. Widgets, which make use of the
ViewPort's functionality can receive the absolute width and height
occupied by the ViewPorts child(ren) using the 'real_width' and
'real_height' attributes and their respective methods.
# Get the total width and height occupied by the ViewPort child.
abswidth = viewport.real_width
absheight = viewport.get_real_height ()
Concrete usage and inheritance implementations of the ViewPort can
be found in the ScrolledWindow, ListViewPort and ScrolledList
classes.
Default action (invoked by activate()):
None
Mnemonic action (invoked by activate_mnemonic()):
None
Attributes:
"""
def __init__ (self, widget):
Bin.__init__ (self)
self._hadjustment = 0
self._vadjustment = 0
if widget:
self.minsize = widget.size
else:
self.minsize = 10, 10
self.child = widget
def set_focus (self, focus=True):
"""V.set_focus (focus=True) -> None
Overrides the set_focus() behaviour for the ViewPort.
The ViewPort class is not focusable by default. It is a layout
class for other widgets, so it does not need to get the input
focus and thus it will return false without doing anything.
"""
return False
def set_hadjustment (self, value):
"""V.set_hadjustment (...) -> None
Sets the horizontal adjustment to scroll.
Raises a TypeError, if the passed argument is not an integer.
"""
if type (value) != int:
raise TypeError ("value must be an integer")
self._hadjustment = value
self.dirty = True
def set_vadjustment (self, value):
"""V.set_vadjustment (...) -> None
Sets the vertical adjustment to scroll.
Raises a TypeError, if the passed argument is not an integer.
"""
if type (value) != int:
raise TypeError ("value must be an integer")
self._vadjustment = value
self.dirty = True
def get_real_width (self):
"""V.get_real_width () -> int
Gets the real width occupied by the ViewPort.
"""
if self.child:
return self.child.width
return self.width
def get_real_height (self):
"""V.get_real_height () -> int
Gets the real height occupied by the ViewPort.
"""
if self.child:
return self.child.height
return self.height
def rect_to_client (self, rect=None):
"""V.rect_to_client () -> pygame.Rect
Returns the absolute coordinates a rect is located at.
If a rect argument is passed, its size and position are modified
to match the criteria of the scrolling adjustments of the
ViewPort. Besides that it exactly behaves like the original
rect_to_client() method.
"""
if rect:
border = base.GlobalStyle.get_border_size \
(self.__class__, self.style,
StyleInformation.get ("VIEWPORT_BORDER"))
rect.x = self.x + rect.x
rect.y = self.y + rect.y
if rect.right > self.right - border:
rect.width = self.right - border - rect.left
if rect.bottom > self.bottom - border:
rect.height = self.bottom - border - rect.top
if (self.parent != None) and isinstance (self.parent, BaseWidget):
return self.parent.rect_to_client (rect)
return rect
return Bin.rect_to_client (self)
def draw_bg (self):
"""V.draw_bg () -> Surface
Draws the ViewPort background surface and returns it.
Creates the visible surface of the ViewPort and returns it to the
caller.
"""
return base.GlobalStyle.engine.draw_viewport (self)
def draw (self):
"""V.draw () -> None
Draws the ViewPort surface and places its child on it.
"""
border = base.GlobalStyle.get_border_size \
(self.__class__, self.style,
StyleInformation.get ("VIEWPORT_BORDER"))
Bin.draw (self)
if self.child:
self.child.topleft = border + self.hadjustment, \
border + self.vadjustment
self.image.blit (self.child.image, (border, border),
(abs (self.hadjustment), abs (self.vadjustment),
self.width - 2 * border,
self.height - 2 * border))
def update (self, **kwargs):
"""V.update (...) -> None
Updates the ViewPort.
Updates the ViewPort and causes its parent to update itself on
demand.
"""
if not self.dirty:
border = base.GlobalStyle.get_border_size \
(self.__class__, self.style,
StyleInformation.get ("VIEWPORT_BORDER"))
resize = kwargs.get ("resize", False)
children = kwargs.get ("children", {})
blit = self.image.blit
items = children.items ()
# Clean up the dirty areas on the widget.
vals = []
for child, rect in items:
blit (self._bg, rect, rect)
# r will be the area for the blit.
r = Rect (abs (self.hadjustment), abs (self.vadjustment),
self.width - 2 * border, self.height - 2 * border)
blit (child.image, (border, border), r)
vals.append (r)
# If a parent's available, reassign the child rects, so that
# they point to the absolute position on the widget and build
# one matching them all for an update.
if self.parent:
rect = Rect (self._oldrect)
if len (vals) != 0:
for r in vals:
r.x += self.x
r.y += self.y
rect.unionall (vals[1:])
self.parent.update (children={ self : rect }, resize=resize)
self._lock = max (self._lock - 1, 0)
else:
Bin.update (self, **kwargs)
hadjustment = property (lambda self: self._hadjustment,
lambda self, var: self.set_hadjustment (var),
doc = "The horizontal scrolling adjustment.")
vadjustment = property (lambda self: self._vadjustment,
lambda self, var: self.set_vadjustment (var),
doc = "The vertical scrolling adjustment.")
real_width = property (lambda self: self.get_real_width (),
doc = "The real width occupied by the ViewPort.")
real_height = property (lambda self: self.get_real_height (),
doc = "The real height occupied by the ViewPort.")
syntax highlighted by Code2HTML, v. 0.9.1