Module albow.containers.PaletteView
Source code
import logging
from pygame import Rect
from pygame import Surface
from pygame import draw
from pygame.event import Event
from albow.containers.GridView import GridView
from albow.utils import frame_rect
from albow.themes.ThemeProperty import ThemeProperty
class PaletteView(GridView):
"""
The PaletteView class is an abstract base class for implementing tool palettes and similar things. A PaletteView
displays an array of items which can be selected by clicking, with the selected item being highlighted. There
is provision for scrolling, so that the palette can contain more items than are displayed at one time.
The PaletteView does not maintain the items themselves or keep track of which one is selected; these things
are responsibilities of the subclass.
"""
"""
nrows int No. of displayed rows
ncols int No. of displayed columns
Abstract methods:
num_items() --> no. of items
draw_item(surface, item_no, rect)
"""
sel_width = ThemeProperty('sel_width')
"""
Width of the border drawn around the selected item when the highlight_style is 'frame'.
"""
scroll_button_size = ThemeProperty('scroll_button_size')
"""
Size of the scrolling buttons. (This is a number, not a tuple -- the scroll buttons are square.)
"""
scroll_button_color = ThemeProperty('scroll_button_color')
"""
Color in which to draw the scrolling buttons.
"""
highlight_style = ThemeProperty('highlight_style')
"""
Determines the way in which a selected cell is highlighted. Values are:
- _frame_ to draw a frame around the cell
- _fill_ to fill its background with the sel_color
- _reverse_ to swap the foreground and background colours
- _arrows_
"""
def __init__(self, cell_size, nrows, ncols, scrolling=False, **kwds):
"""
Initializes the palette view with the specified cell_size, and a rect sized for displaying
nrows rows and ncols columns of items. If scrolling is true, controls will be
displayed for scrolling the view.
Args:
cell_size: A tuple that specifies the cell size (width, height)
nrows: The # of rows
ncols: The # of columns
scrolling: True to display scroll bars, else false
**kwds:
"""
self.logger = logging.getLogger(__name__)
#
# Python 3 update
#
# GridView.__init__(self, cell_size, nrows, ncols, **kwds)
super().__init__(cell_size, nrows, ncols, **kwds)
self.scrolling = scrolling
if scrolling:
d = self.scroll_button_size
#l = self.width
#b = self.height
self.width += d
# self.scroll_up_rect = Rect(l, 0, d, d).inflate(-4, -4)
# self.scroll_down_rect = Rect(l, b - d, d, d).inflate(-4, -4)
self.scroll = 0
def scroll_up_rect(self):
d = self.scroll_button_size
r = Rect(0, 0, d, d)
m = self.margin
r.top = m
r.right = self.width - m
r.inflate_ip(-4, -4)
return r
def scroll_down_rect(self):
d = self.scroll_button_size
r = Rect(0, 0, d, d)
m = self.margin
r.bottom = self.height - m
r.right = self.width - m
r.inflate_ip(-4, -4)
return r
def draw(self, surface):
GridView.draw(self, surface)
if self.can_scroll_up():
self.draw_scroll_up_button(surface)
if self.can_scroll_down():
self.draw_scroll_down_button(surface)
def draw_scroll_up_button(self, surface):
r = self.scroll_up_rect()
c = self.scroll_button_color
draw.polygon(surface, c, [r.bottomleft, r.midtop, r.bottomright])
def draw_scroll_down_button(self, surface):
r = self.scroll_down_rect()
c = self.scroll_button_color
draw.polygon(surface, c, [r.topleft, r.midbottom, r.topright])
def draw_cell(self, surface, row, col, rect):
i = self.cell_to_item_no(row, col)
if i is not None:
highlight = self.item_is_selected(i)
self.draw_item_and_highlight(surface, i, rect, highlight)
def draw_item_with(self, surface, i, rect, fg):
old_fg = self.fg_color
self.fg_color = fg
try:
self.draw_item(surface, i, rect)
finally:
self.fg_color = old_fg
def draw_prehighlight_with(self, theSurface: Surface, theItemNumber: int, theRect: Rect, color):
style = self.highlight_style
if style == 'frame':
frame_rect(theSurface, color, theRect, self.sel_width)
elif style == 'fill' or style == 'reverse':
theSurface.fill(color, theRect)
def mouse_down(self, event):
if self.scrolling:
p = event.local
#
# Python 3 method signature update for tuples
# break up to make easier to debug
#
scrollDownRect: Rect = self.scroll_down_rect()
scrollUpRect: Rect = self.scroll_up_rect()
canScrollDown: bool = scrollDownRect.collidepoint(p[0], p[1])
canScrollUp: bool = scrollUpRect.collidepoint(p[0], p[1])
self.logger.debug(f"p: {p}, downRect.centerx {scrollDownRect.centerx}, downRect.centery {scrollDownRect.centery}")
# if self.scroll_up_rect().collidepoint(p):
if canScrollUp:
self.scroll_up()
return
# elif self.scroll_down_rect().collidepoint(p):
elif canScrollDown:
self.scroll_down()
return
GridView.mouse_down(self, event)
def scroll_up(self):
if self.can_scroll_up():
self.scroll -= self.items_per_page()
def scroll_down(self):
if self.can_scroll_down():
self.scroll += self.items_per_page()
def scroll_to_item(self, n):
i = max(0, min(n, self.num_items() - 1))
p = self.items_per_page()
self.scroll = p * (i // p)
def can_scroll_up(self):
return self.scrolling and self.scroll > 0
def can_scroll_down(self):
return self.scrolling and self.scroll + self.items_per_page() < self.num_items()
def items_per_page(self):
return self.num_rows() * self.num_cols()
def click_cell(self, row, col, event):
i = self.cell_to_item_no(row, col)
if i is not None:
self.click_item(i, event)
def cell_to_item_no(self, row, col):
i = self.scroll + row * self.num_cols() + col
if 0 <= i < self.num_items():
return i
else:
return None
def num_rows(self):
ch = self.cell_size[1]
if ch:
return self.height // ch
else:
return 0
def num_cols(self):
width = self.width
if self.scrolling:
width -= self.scroll_button_size
cw = self.cell_size[0]
if cw:
return width // cw
else:
return 0
# ========================================================================
#
# Abstract methods follow; Some implemented with default behavior
#
# ========================================================================
def draw_item_and_highlight(self, theSurface: Surface, theItemNumber: int, theRect: Rect, highlight: bool):
"""
Draws the cell for item theItemNumber, together with highlighting if highlight is true. The default
implementation calls draw_prehighlight, draw_item and draw_posthighlight.
Args:
theSurface: The surface to drawn on
theItemNumber: The item # of highlight
theRect: The pygame rect to use
highlight: If True highlight
Returns:
"""
if highlight:
self.draw_prehighlight(theSurface, theItemNumber, theRect)
if highlight and self.highlight_style == 'reverse':
fg = self.inherited('bg_color') or self.sel_color
else:
fg = self.fg_color
self.draw_item_with(theSurface, theItemNumber, theRect, fg)
if highlight:
self.draw_posthighlight(theSurface, theItemNumber, theRect)
def draw_prehighlight(self, theSurface: Surface, theItemNumber: int, theRect: Rect):
"""
Called for highlighted cells before draw_item, to draw highlighting that is to appear
underneath the cell's contents.
Args:
theSurface:
theItemNumber:
theRect:
"""
if self.highlight_style == 'reverse':
color = self.fg_color
else:
color = self.sel_color
self.draw_prehighlight_with(theSurface, theItemNumber, theRect, color)
def draw_posthighlight(self, theSurface: Surface, theItemNumber: int, theRect: Rect):
"""
Called for highlighted cells after draw_item, to draw highlighting that is to appear
on top of the cell's contents.
Args:
theSurface:
theItemNumber:
theRect:
"""
pass
def item_is_selected(self, theItemNumber: int) -> bool:
"""
Should return a boolean indicating whether item number item_no is currently to be considered selected.
Args:
theItemNumber:
Returns True if it is, False
"""
return False
def click_item(self, theItemNumber: int, theEvent: Event):
"""
Called when a mouse-down event occurs in item theItemNumber. Typically the subclass will record the fact that
the item is selected so that this can be reported later via item_is_selected().
Args:
theItemNumber:
theEvent:
Returns:
"""
pass
Classes
class PaletteView (cell_size, nrows, ncols, scrolling=False, **kwds)
-
The PaletteView class is an abstract base class for implementing tool palettes and similar things. A PaletteView displays an array of items which can be selected by clicking, with the selected item being highlighted. There is provision for scrolling, so that the palette can contain more items than are displayed at one time.
The PaletteView does not maintain the items themselves or keep track of which one is selected; these things are responsibilities of the subclass.
Initializes the palette view with the specified cell_size, and a rect sized for displaying nrows rows and ncols columns of items. If scrolling is true, controls will be displayed for scrolling the view.
Args
cell_size
- A tuple that specifies the cell size (width, height)
nrows
-
The # of rows
ncols
-
The # of columns
scrolling
- True to display scroll bars, else false
**kwds:
Source code
class PaletteView(GridView): """ The PaletteView class is an abstract base class for implementing tool palettes and similar things. A PaletteView displays an array of items which can be selected by clicking, with the selected item being highlighted. There is provision for scrolling, so that the palette can contain more items than are displayed at one time. The PaletteView does not maintain the items themselves or keep track of which one is selected; these things are responsibilities of the subclass. """ """ nrows int No. of displayed rows ncols int No. of displayed columns Abstract methods: num_items() --> no. of items draw_item(surface, item_no, rect) """ sel_width = ThemeProperty('sel_width') """ Width of the border drawn around the selected item when the highlight_style is 'frame'. """ scroll_button_size = ThemeProperty('scroll_button_size') """ Size of the scrolling buttons. (This is a number, not a tuple -- the scroll buttons are square.) """ scroll_button_color = ThemeProperty('scroll_button_color') """ Color in which to draw the scrolling buttons. """ highlight_style = ThemeProperty('highlight_style') """ Determines the way in which a selected cell is highlighted. Values are: - _frame_ to draw a frame around the cell - _fill_ to fill its background with the sel_color - _reverse_ to swap the foreground and background colours - _arrows_ """ def __init__(self, cell_size, nrows, ncols, scrolling=False, **kwds): """ Initializes the palette view with the specified cell_size, and a rect sized for displaying nrows rows and ncols columns of items. If scrolling is true, controls will be displayed for scrolling the view. Args: cell_size: A tuple that specifies the cell size (width, height) nrows: The # of rows ncols: The # of columns scrolling: True to display scroll bars, else false **kwds: """ self.logger = logging.getLogger(__name__) # # Python 3 update # # GridView.__init__(self, cell_size, nrows, ncols, **kwds) super().__init__(cell_size, nrows, ncols, **kwds) self.scrolling = scrolling if scrolling: d = self.scroll_button_size #l = self.width #b = self.height self.width += d # self.scroll_up_rect = Rect(l, 0, d, d).inflate(-4, -4) # self.scroll_down_rect = Rect(l, b - d, d, d).inflate(-4, -4) self.scroll = 0 def scroll_up_rect(self): d = self.scroll_button_size r = Rect(0, 0, d, d) m = self.margin r.top = m r.right = self.width - m r.inflate_ip(-4, -4) return r def scroll_down_rect(self): d = self.scroll_button_size r = Rect(0, 0, d, d) m = self.margin r.bottom = self.height - m r.right = self.width - m r.inflate_ip(-4, -4) return r def draw(self, surface): GridView.draw(self, surface) if self.can_scroll_up(): self.draw_scroll_up_button(surface) if self.can_scroll_down(): self.draw_scroll_down_button(surface) def draw_scroll_up_button(self, surface): r = self.scroll_up_rect() c = self.scroll_button_color draw.polygon(surface, c, [r.bottomleft, r.midtop, r.bottomright]) def draw_scroll_down_button(self, surface): r = self.scroll_down_rect() c = self.scroll_button_color draw.polygon(surface, c, [r.topleft, r.midbottom, r.topright]) def draw_cell(self, surface, row, col, rect): i = self.cell_to_item_no(row, col) if i is not None: highlight = self.item_is_selected(i) self.draw_item_and_highlight(surface, i, rect, highlight) def draw_item_with(self, surface, i, rect, fg): old_fg = self.fg_color self.fg_color = fg try: self.draw_item(surface, i, rect) finally: self.fg_color = old_fg def draw_prehighlight_with(self, theSurface: Surface, theItemNumber: int, theRect: Rect, color): style = self.highlight_style if style == 'frame': frame_rect(theSurface, color, theRect, self.sel_width) elif style == 'fill' or style == 'reverse': theSurface.fill(color, theRect) def mouse_down(self, event): if self.scrolling: p = event.local # # Python 3 method signature update for tuples # break up to make easier to debug # scrollDownRect: Rect = self.scroll_down_rect() scrollUpRect: Rect = self.scroll_up_rect() canScrollDown: bool = scrollDownRect.collidepoint(p[0], p[1]) canScrollUp: bool = scrollUpRect.collidepoint(p[0], p[1]) self.logger.debug(f"p: {p}, downRect.centerx {scrollDownRect.centerx}, downRect.centery {scrollDownRect.centery}") # if self.scroll_up_rect().collidepoint(p): if canScrollUp: self.scroll_up() return # elif self.scroll_down_rect().collidepoint(p): elif canScrollDown: self.scroll_down() return GridView.mouse_down(self, event) def scroll_up(self): if self.can_scroll_up(): self.scroll -= self.items_per_page() def scroll_down(self): if self.can_scroll_down(): self.scroll += self.items_per_page() def scroll_to_item(self, n): i = max(0, min(n, self.num_items() - 1)) p = self.items_per_page() self.scroll = p * (i // p) def can_scroll_up(self): return self.scrolling and self.scroll > 0 def can_scroll_down(self): return self.scrolling and self.scroll + self.items_per_page() < self.num_items() def items_per_page(self): return self.num_rows() * self.num_cols() def click_cell(self, row, col, event): i = self.cell_to_item_no(row, col) if i is not None: self.click_item(i, event) def cell_to_item_no(self, row, col): i = self.scroll + row * self.num_cols() + col if 0 <= i < self.num_items(): return i else: return None def num_rows(self): ch = self.cell_size[1] if ch: return self.height // ch else: return 0 def num_cols(self): width = self.width if self.scrolling: width -= self.scroll_button_size cw = self.cell_size[0] if cw: return width // cw else: return 0 # ======================================================================== # # Abstract methods follow; Some implemented with default behavior # # ======================================================================== def draw_item_and_highlight(self, theSurface: Surface, theItemNumber: int, theRect: Rect, highlight: bool): """ Draws the cell for item theItemNumber, together with highlighting if highlight is true. The default implementation calls draw_prehighlight, draw_item and draw_posthighlight. Args: theSurface: The surface to drawn on theItemNumber: The item # of highlight theRect: The pygame rect to use highlight: If True highlight Returns: """ if highlight: self.draw_prehighlight(theSurface, theItemNumber, theRect) if highlight and self.highlight_style == 'reverse': fg = self.inherited('bg_color') or self.sel_color else: fg = self.fg_color self.draw_item_with(theSurface, theItemNumber, theRect, fg) if highlight: self.draw_posthighlight(theSurface, theItemNumber, theRect) def draw_prehighlight(self, theSurface: Surface, theItemNumber: int, theRect: Rect): """ Called for highlighted cells before draw_item, to draw highlighting that is to appear underneath the cell's contents. Args: theSurface: theItemNumber: theRect: """ if self.highlight_style == 'reverse': color = self.fg_color else: color = self.sel_color self.draw_prehighlight_with(theSurface, theItemNumber, theRect, color) def draw_posthighlight(self, theSurface: Surface, theItemNumber: int, theRect: Rect): """ Called for highlighted cells after draw_item, to draw highlighting that is to appear on top of the cell's contents. Args: theSurface: theItemNumber: theRect: """ pass def item_is_selected(self, theItemNumber: int) -> bool: """ Should return a boolean indicating whether item number item_no is currently to be considered selected. Args: theItemNumber: Returns True if it is, False """ return False def click_item(self, theItemNumber: int, theEvent: Event): """ Called when a mouse-down event occurs in item theItemNumber. Typically the subclass will record the fact that the item is selected so that this can be reported later via item_is_selected(). Args: theItemNumber: theEvent: Returns: """ pass
Ancestors
Subclasses
- TableRowBase
- MultiChoice
- FileListView
- ListBox
- albow.demo.views.DemoPaletteView.DemoPaletteView
Class variables
var highlight_style
-
Determines the way in which a selected cell is highlighted. Values are:
- frame to draw a frame around the cell
- fill to fill its background with the sel_color
- reverse to swap the foreground and background colours
- arrows
-
Color in which to draw the scrolling buttons.
-
Size of the scrolling buttons. (This is a number, not a tuple – the scroll buttons are square.)
var sel_width
-
Width of the border drawn around the selected item when the highlight_style is 'frame'.
Methods
def can_scroll_down(self)
-
Source code
def can_scroll_down(self): return self.scrolling and self.scroll + self.items_per_page() < self.num_items()
def can_scroll_up(self)
-
Source code
def can_scroll_up(self): return self.scrolling and self.scroll > 0
def cell_to_item_no(self, row, col)
-
Source code
def cell_to_item_no(self, row, col): i = self.scroll + row * self.num_cols() + col if 0 <= i < self.num_items(): return i else: return None
def click_cell(self, row, col, event)
-
Source code
def click_cell(self, row, col, event): i = self.cell_to_item_no(row, col) if i is not None: self.click_item(i, event)
def click_item(self, theItemNumber, theEvent)
-
Called when a mouse-down event occurs in item theItemNumber. Typically the subclass will record the fact that the item is selected so that this can be reported later via item_is_selected().
Args
theItemNumber: theEvent: Returns:
Source code
def click_item(self, theItemNumber: int, theEvent: Event): """ Called when a mouse-down event occurs in item theItemNumber. Typically the subclass will record the fact that the item is selected so that this can be reported later via item_is_selected(). Args: theItemNumber: theEvent: Returns: """ pass
def draw_cell(self, surface, row, col, rect)
-
Source code
def draw_cell(self, surface, row, col, rect): i = self.cell_to_item_no(row, col) if i is not None: highlight = self.item_is_selected(i) self.draw_item_and_highlight(surface, i, rect, highlight)
def draw_item_and_highlight(self, theSurface, theItemNumber, theRect, highlight)
-
Draws the cell for item theItemNumber, together with highlighting if highlight is true. The default implementation calls draw_prehighlight, draw_item and draw_posthighlight.
Args
theSurface
-
The surface to drawn on
theItemNumber
- The item # of highlight
theRect
-
The pygame rect to use
highlight
-
If True highlight
Returns:
Source code
def draw_item_and_highlight(self, theSurface: Surface, theItemNumber: int, theRect: Rect, highlight: bool): """ Draws the cell for item theItemNumber, together with highlighting if highlight is true. The default implementation calls draw_prehighlight, draw_item and draw_posthighlight. Args: theSurface: The surface to drawn on theItemNumber: The item # of highlight theRect: The pygame rect to use highlight: If True highlight Returns: """ if highlight: self.draw_prehighlight(theSurface, theItemNumber, theRect) if highlight and self.highlight_style == 'reverse': fg = self.inherited('bg_color') or self.sel_color else: fg = self.fg_color self.draw_item_with(theSurface, theItemNumber, theRect, fg) if highlight: self.draw_posthighlight(theSurface, theItemNumber, theRect)
def draw_item_with(self, surface, i, rect, fg)
-
Source code
def draw_item_with(self, surface, i, rect, fg): old_fg = self.fg_color self.fg_color = fg try: self.draw_item(surface, i, rect) finally: self.fg_color = old_fg
def draw_posthighlight(self, theSurface, theItemNumber, theRect)
-
Called for highlighted cells after draw_item, to draw highlighting that is to appear on top of the cell's contents.
Args
theSurface: theItemNumber: theRect:
Source code
def draw_posthighlight(self, theSurface: Surface, theItemNumber: int, theRect: Rect): """ Called for highlighted cells after draw_item, to draw highlighting that is to appear on top of the cell's contents. Args: theSurface: theItemNumber: theRect: """ pass
def draw_prehighlight(self, theSurface, theItemNumber, theRect)
-
Called for highlighted cells before draw_item, to draw highlighting that is to appear underneath the cell's contents.
Args
theSurface: theItemNumber: theRect:
Source code
def draw_prehighlight(self, theSurface: Surface, theItemNumber: int, theRect: Rect): """ Called for highlighted cells before draw_item, to draw highlighting that is to appear underneath the cell's contents. Args: theSurface: theItemNumber: theRect: """ if self.highlight_style == 'reverse': color = self.fg_color else: color = self.sel_color self.draw_prehighlight_with(theSurface, theItemNumber, theRect, color)
def draw_prehighlight_with(self, theSurface, theItemNumber, theRect, color)
-
Source code
def draw_prehighlight_with(self, theSurface: Surface, theItemNumber: int, theRect: Rect, color): style = self.highlight_style if style == 'frame': frame_rect(theSurface, color, theRect, self.sel_width) elif style == 'fill' or style == 'reverse': theSurface.fill(color, theRect)
-
Source code
def draw_scroll_down_button(self, surface): r = self.scroll_down_rect() c = self.scroll_button_color draw.polygon(surface, c, [r.topleft, r.midbottom, r.topright])
-
Source code
def draw_scroll_up_button(self, surface): r = self.scroll_up_rect() c = self.scroll_button_color draw.polygon(surface, c, [r.bottomleft, r.midtop, r.bottomright])
def item_is_selected(self, theItemNumber)
-
Should return a boolean indicating whether item number item_no is currently to be considered selected.
Args
theItemNumber: Returns True if it is, False
Source code
def item_is_selected(self, theItemNumber: int) -> bool: """ Should return a boolean indicating whether item number item_no is currently to be considered selected. Args: theItemNumber: Returns True if it is, False """ return False
def items_per_page(self)
-
Source code
def items_per_page(self): return self.num_rows() * self.num_cols()
def mouse_down(self, event)
-
Source code
def mouse_down(self, event): if self.scrolling: p = event.local # # Python 3 method signature update for tuples # break up to make easier to debug # scrollDownRect: Rect = self.scroll_down_rect() scrollUpRect: Rect = self.scroll_up_rect() canScrollDown: bool = scrollDownRect.collidepoint(p[0], p[1]) canScrollUp: bool = scrollUpRect.collidepoint(p[0], p[1]) self.logger.debug(f"p: {p}, downRect.centerx {scrollDownRect.centerx}, downRect.centery {scrollDownRect.centery}") # if self.scroll_up_rect().collidepoint(p): if canScrollUp: self.scroll_up() return # elif self.scroll_down_rect().collidepoint(p): elif canScrollDown: self.scroll_down() return GridView.mouse_down(self, event)
def scroll_down(self)
-
Source code
def scroll_down(self): if self.can_scroll_down(): self.scroll += self.items_per_page()
def scroll_down_rect(self)
-
Source code
def scroll_down_rect(self): d = self.scroll_button_size r = Rect(0, 0, d, d) m = self.margin r.bottom = self.height - m r.right = self.width - m r.inflate_ip(-4, -4) return r
def scroll_to_item(self, n)
-
Source code
def scroll_to_item(self, n): i = max(0, min(n, self.num_items() - 1)) p = self.items_per_page() self.scroll = p * (i // p)
def scroll_up(self)
-
Source code
def scroll_up(self): if self.can_scroll_up(): self.scroll -= self.items_per_page()
def scroll_up_rect(self)
-
Source code
def scroll_up_rect(self): d = self.scroll_button_size r = Rect(0, 0, d, d) m = self.margin r.top = m r.right = self.width - m r.inflate_ip(-4, -4) return r
Inherited members
GridView
:add
add_anchor
add_centered
anchor
attention_lost
augment_mouse_event
bg_color
bg_image
border_color
border_width
call_handler
call_parent_handler
cell_rect
defer_drawing
dismiss
draw
draw_over
fg_color
focus
focus_switch
font
get_cursor
get_focus
get_margin_rect
get_root
get_top_widget
get_visible
global_to_local
has_focus
inherited
invalidate
is_gl_container
key_down
key_up
local_to_global
margin
menu_bar
num_cols
num_rows
parent
parent_resized
present
rect
relative_mode
remove
remove_anchor
resized
scale_bg
sel_color
set_parent
set_size_for_text
tab_stop
visible