# $Id: ListViewPort.py,v 1.14.2.3 2006/09/16 11:28:20 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.
"""ViewPort proxy class for the ScrolledList."""
from pygame import Rect
from ocempgui.draw import Draw
from ocempgui.widgets.components import ListItemCollection
from ocempgui.widgets.components import TextListItem, FileListItem
from ViewPort import ViewPort
from Bin import Bin
from Constants import *
from StyleInformation import StyleInformation
import base
class ListViewPort (ViewPort):
"""ListViewPort (scrolledlist) -> ListViewPort
A ViewPort proxy for ListItem objects.
The ListViewPort is a proxy class, which is attached as widget to
the ScrolledList. It takes care of updating and drawing the attached
list items.
The ListViewPort implements out-of-the-box support for the
TextListItem and FileListItem classes and possible inheritors of
those. If you want to to draw an own ListItem type, you should
create a subclass, which overrides the draw_item() method according
to your needs.
To guarantee a correct behaviour, the attributes or methods of the
ListViewPort should not be modified at runtime in any way. Instead a
subclass should be created, which overrides the necessary parts.
Default action (invoked by activate()):
None
Mnemonic action (invoked by activate_mnemonic()):
None
Attributes:
images - A dict containing the surfaces for the attached items.
scrolledlist - The ScrolledList, the ListViewPort is attached to.
"""
def __init__ (self, scrolledlist):
self._scrolledlist = scrolledlist
self._images = {}
self._realwidth = 0
self._realheight = 0
ViewPort.__init__ (self, None)
def get_real_width (self):
"""L.get_real_width () -> int
Gets the real width occupied by the ListViewPort.
"""
return self._realwidth
def get_real_height (self):
"""L.get_real_height () -> int
Gets the real height occupied by the ListViewPort.
"""
return self._realheight
def get_item_at_pos (self, position):
"""L.get_item_at_pos (...) -> ListItem
Gets the item at the passed position coordinates.
"""
eventarea = self.rect_to_client ()
if not eventarea.collidepoint (position):
return None
position = position[0] - eventarea.left, position[1] - eventarea.top
border = base.GlobalStyle.get_border_size \
(self.__class__, self.style,
StyleInformation.get ("ACTIVE_BORDER")) * 2
posy = self.vadjustment
items = self.scrolledlist.items
width = eventarea.width
bottom = eventarea.bottom
images = self.images
spacing = self.scrolledlist.spacing
for item in items:
rect = Rect (images [item][1])
rect.y = posy
rect.width = width + border
if rect.bottom > bottom:
rect.height = bottom - rect.bottom + border
if rect.collidepoint (position):
return item
posy += images[item][1].height + spacing + border
return None
def get_item_position (self, item):
"""L.get_item_position (...) -> int, int
Gets the relative position coordinates of an item.
"""
y = 0
items = self.scrolledlist.items
active = base.GlobalStyle.get_border_size \
(self.__class__, self.style,
StyleInformation.get ("ACTIVE_BORDER")) * 2
spacing = self.scrolledlist.spacing
border = base.GlobalStyle.get_border_size \
(self.__class__, self.style,
StyleInformation.get ("VIEWPORT_BORDER"))
for it in items:
if it == item:
break
y += self._images[item][1].height + spacing + active
return self.left + border, self.top + y + border
def update_items (self):
"""L.update_items () -> None
Updates the attached items of the ScrolledList.
"""
draw_item = self.draw_item
spacing = self.scrolledlist.spacing
width, height = 0, 0
items = self.scrolledlist.items
engine = base.GlobalStyle.engine
border = base.GlobalStyle.get_border_size \
(self.__class__, self.style,
StyleInformation.get ("ACTIVE_BORDER")) * 2
for item in items:
if item.dirty:
item.dirty = False
rect = draw_item (item, engine)[1]
else:
rect = self._images[item][1]
if width < rect.width:
width = rect.width
height += rect.height + spacing + border
# The last item does not need any spacing.
if height > 0:
height -= spacing
# Set the step value of the attached scrolledlist.
step = 1
if items.length > 0:
step = height / items.length + spacing / 2
self.scrolledlist.vscrollbar.step = step
self._realwidth = width + border
self._realheight = height
self.dirty = True
def draw_item (self, item, engine):
"""L.draw_item (...) -> Surface
Redraws a sepcific item.
"""
surface = None
if isinstance (item, FileListItem):
surface = engine.draw_filelistitem (self, item)
elif isinstance (item, TextListItem):
surface = engine.draw_textlistitem (self, item)
else:
raise TypeError ("Unsupported item type %s" % type (item))
val = (surface, surface.get_rect ())
self._images[item] = val
return val
def draw (self):
"""L.draw () -> None
Draws the ListViewPort surface and places its items on it.
"""
Bin.draw (self)
style = base.GlobalStyle
cls = self.__class__
color = StyleInformation.get ("SELECTION_COLOR")
active = StyleInformation.get ("ACTIVE_BORDER")
border_active = style.get_border_size (cls, self.style, active)
border = style.get_border_size \
(cls, self.style, StyleInformation.get ("VIEWPORT_BORDER"))
active_space = StyleInformation.get ("ACTIVE_BORDER_SPACE")
st = self.style
state = self.state
realwidth = self.real_width
posy = 0
draw_rect = Draw.draw_rect
sdraw_rect = style.engine.draw_rect
sdraw_border = style.engine.draw_border
spacing = self.scrolledlist.spacing
width = self.width - 2 * border
height = self.height - 2 * border
selheight = 0
surface = None
cursor_found = False
cursor = self.scrolledlist.cursor
items = self.scrolledlist.items
focus = self.scrolledlist.focus
images = self.images
lower = abs (self.vadjustment) - spacing - 2 * border_active
upper = abs (self.vadjustment) + height
# Overall surface
surface_all = sdraw_rect (max (realwidth, width), self.real_height,
state, cls, st)
blit = surface_all.blit
for item in items:
image, rect = images[item]
# Draw only those which are visible.
if (posy + rect.height < lower):
posy += rect.height + 2 * border_active + spacing
continue
elif posy > upper:
break
selheight = rect.height + 2 * border_active
if item.selected:
# Highlight the selection.
surface = draw_rect (max (width, realwidth), selheight, color)
# Show input focus.
if focus and (item == cursor):
sdraw_border (surface, state, cls, st, active,
space=active_space)
cursor_found = True
surface.blit (image, (border_active, border_active))
blit (surface, (0, posy))
elif focus and not cursor_found and (item == cursor):
# Input focus.
surface = sdraw_rect (max (width, realwidth), selheight, state,
cls, st)
sdraw_border (surface, state, cls, st, active,
space=active_space)
surface.blit (image, (border_active, border_active))
cursor_found = True
blit (surface, (0, posy))
else:
# Regular image, move by the active border, so that
# all items have the correct offset.
blit (image, (border_active, posy + border_active))
posy += selheight + spacing
self.image.blit (surface_all, (border, border),
(abs (self.hadjustment), abs (self.vadjustment),
width, height))
images = property (lambda self: self._images,
doc = "Dictionary of the item surfaces.")
scrolledlist = property (lambda self: self._scrolledlist,
doc = "The ScrolledList of the ListViewPort.")
syntax highlighted by Code2HTML, v. 0.9.1