# $Id: Magnifier.py,v 1.1.2.7 2007/01/23 22:39:23 marcusva Exp $
#
# Copyright (c) 2006-2007, 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.
"""Magnification tool for pygame."""
import pygame
class Magnifier (object):
"""Magnifier (size=(20, 20), factor=2) -> Magnifier
A screen magnification class for the pygame screen.
The Magnifier class allows to zoom a certain portion of the screen,
determined by the current mouse position by a specific scaling
factor. It creates a rectangular zoom area that will be blit on the
screen. The zooming area will be placed around the current mouse
position:
##############################################
# # ###
# --------------- # # # - pygame screen
# |\ /| # ###
# | \ / | #
# | \ooooooo/ | # ooo
# | o o | # o o - Area to zoom (size)
# | o X o | # ooo
# | o o | #
# | /ooooooo\ | # ---
# | / \ | # | | - Zoomed area.
# |/ \| # ---
# --------------- #
# # X - Mouse cursor position.
##############################################
The size of the area to zoom can be adjusted using the 'size'
attribute and set_size() method.
# Zoom a 40x40 px area around the mouse cursor.
magnifier.size = 40, 40
magnifier.set_size (40, 40)
The factor by which the area around the mouse cursor should be
magnified can be set using the 'factor' attribute or set_factor() method.
# Zoom the wanted area by 3 with a result of an area three times as big
# as the original one.
magnifier.factor = 3
magnifier.set_factor (3)
By default the Magnifier uses a simple call to pygame.transform.scale(),
which does not provide optimal results for each surface. The 'zoom_func'
attribute and set_zoom_func() method allow you to provide an own zoom
function, which has to return the zoomed surface. It receives the actual
screen surface, the mouse position the zoomed area will be centered at and
the sizes and scaling factor to use for zooming.
def own_zoom_func (screen, mousepos, resultsize, size, factor):
...
return zoomed_surface
magnifier.zoom_func = own_zoom_func
magnifier.set_zoom_func (own_zoom_func)
The resultsize is a tuple containing the magnifier size multiplied with the
set factor of the magnifier:
resultsize = int (size[0] * factor), int (size[1] * factor)
size and factor contain the currently set values of the respective
attributes of the Magnifier instance. An implementation of the default zoom
functionality of the Magnifier using the 'zoom_func' attribute would look
like the following:
def own_zoom_func (screen, mousepos, resultsize, size, factor):
offset = mousepos[0] - size[0] / 2, mousepos[1] - size[1] / 2
# Create zoomable surface.
surface = pygame.Surface ((size[0], size[1]))
surface.blit (screen, (0, 0), (offset[0], offset[1], size[0], size[1]))
# Zoom and blit.
return pygame.transform.scale (surface, (resultsize[0], resultsize[1]))
Attributes:
factor - The zoom factor to use for magnification.
size - The size of the area around the mouse cursor to zoom.
border - Indicates whether a 1px border around the magnified area should
be drawn.
zoom_func -
"""
def __init__ (self, size=(20, 20), factor=2):
self._factor = factor
self._size = size
self._oldsurface = None
self._oldpos = None # The topleft offset of the area.
self._mousepos = None # The mouse position.
self._border = True
self._zoomfunc = None
def set_factor (self, factor):
"""M.set_factor (...) -> None
Sets the zoom factor to use for magnification.
Raises a TypeError, if the argument is not an integer or float.
Raises a ValueError, if the argument is smaller than 1.
"""
if type (factor) not in (int, float):
raise TypeError ("factor must be an integer or float")
if factor < 1:
raise ValueError ("factor must not be smaller than 1")
self._factor = factor
if self._mousepos:
self._update (self._mousepos)
def set_size (self, width, height):
"""M.set_size (...) -> None
Sets the width and height of the area to zoom.
Raises a TypeError, if the arguments are not integers.
Raises a ValueError, if the arguments are smaller than 1.
"""
if (type (width) != int) or (type (height) != int):
raise TypeError ("width and height must be integers")
if (width < 1) or (height < 1):
raise ValueError ("width and height must not be smaller than 1")
self._size = width, height
if self._mousepos:
self._update (self._mousepos)
def enable_border (self, border):
"""M.enable_border (...) -> None
Enables or disables the display of a 1px border around the zoom area.
The argument will be interpreted as boolean value.
"""
self._border = border
if self._mousepos:
self._update (self._mousepos)
def restore (self):
"""M.restore () -> None
Restores the original screen content.
"""
screen = pygame.display.get_surface ()
# Restore old surface area.
if self._oldsurface:
screen.blit (self._oldsurface, self._oldpos)
self._oldsurface = None
def set_zoom_func (self, func):
"""D.set_zoom_func (...) -> None
Sets the zoom function to use for the Magnifier..
Raises a TypeError, if func is not callable.
"""
if not callable (func):
raise TypeError ("func must be callable")
self._zoomfunc = func
if self._mousepos:
self._update (self._mousepos)
def notify (self, *events):
"""M.notify (...) -> bool
Notifies the Magnifier about a pygame.event.Event.
The argument must be a pygame.event.Event.
"""
motion = [e for e in events if e.type == pygame.MOUSEMOTION]
if motion:
self._mousepos = motion[-1].pos
self._update (self._mousepos)
return True
# Update the screen for the case it changed.
if self._mousepos:
self._update (self._mousepos)
return False
def _update (self, position):
"""M._update (...) -> None
Update the magnification area.
"""
surface = None
screen = pygame.display.get_surface ()
rsize = int (self.size[0] * self.factor), \
int (self.size[1] * self.factor)
offset = position[0] - rsize[0] / 2, position[1] - rsize[1] / 2
zoffset = position[0] - self.size[0] / 2, position[1] - self.size[1] / 2
# Restore old surface area.
if self._oldsurface:
screen.blit (self._oldsurface, self._oldpos)
# Preserve surface at the position.
self._oldsurface = pygame.Surface ((rsize[0], rsize[1]))
self._oldsurface.blit (screen, (0, 0), (offset[0], offset[1],
rsize[0], rsize[1]))
if self._zoomfunc:
surface = self.zoom_func (screen, position, rsize, self.size,
self.factor)
else:
# Create zoomable surface.
surface = pygame.Surface ((self.size[0], self.size[1]))
surface.blit (screen, (0, 0), (zoffset[0], zoffset[1],
self.size[0], self.size[1]))
# Zoom and blit.
surface = pygame.transform.scale (surface, (rsize[0], rsize[1]))
if self.border:
pygame.draw.line (surface, (0, 0, 0), (0, 0), (0, rsize[1]))
pygame.draw.line (surface, (0, 0, 0), (0, 0), (rsize[0], 0))
pygame.draw.line (surface, (0, 0, 0), (rsize[0] - 1, rsize[1] - 1),
(0, rsize[1] - 1))
pygame.draw.line (surface, (0, 0, 0), (rsize[0] - 1, rsize[1] - 1),
(rsize[0] - 1, 0))
screen.blit (surface, offset)
self._oldpos = offset
size = property (lambda self: self._size,
lambda self, (x, y): self.set_size (x, y),
doc = "The size of the magnification area.")
factor = property (lambda self: self._factor,
lambda self, var: self.set_factor (var),
doc = "The zoom factor of the magnification area.")
border = property (lambda self: self._border,
lambda self, var: self.enable_border (var),
doc = "Indicates whether a border should be shown.")
zoom_func = property (lambda self: self._zoomfunc,
lambda self, var: self.set_zoom_func (var),
doc = "The zoom function to use.")
syntax highlighted by Code2HTML, v. 0.9.1