# --- imports
# pygame imports
import pygame
# local imports
from .selection_text_widget import *
from ..designs import getDefaultDesign
from ..util import inherit_docstrings_from_superclass
# constants
VIEWPOINT = 'v'
[docs]class Listbox(SelectionTextWidget):
    """
    Listbox for displaying lists of multiple objects as strings.
    """
    def __init__(self, x, y, width, height, font=getDefaultDesign().font, editable=False, validation_function=(lambda *x: True), selection_overlay=getDefaultDesign().selection_overlay):
        """
        Initialisation of an Listbox.
        Args:
            inherit_doc:: arguments
        """
        super(Listbox, self).__init__(x, y, width, height, "", font, editable, validation_function, selection_overlay)
        self._list = []
        self.viewpoint = self.cursor
[docs]    def setViewpoint(self, index):
        """
        Set the widget's viewpoint-position.
        Args:
            index: An integer (or known constant) representing the index the viewpoint should be set to.
        Returns:
            Itsself (the widget) for convenience.
        """
        self._viewpoint = self.getActualIndex(index)
        self.markDirty()
        return self 
[docs]    def moveViewpoint(self, index):
        """
        Move the widget's viewpoint-position by the given amount.
        Args:
            amount: An integer representing the amount the viewpoint should be moved by.
        Returns:
            Itsself (the widget) for convenience.
        """
        return self.setViewpoint(self.viewpoint + int(index)) 
[docs]    def getViewpoint(self):
        """
        Return the widget's viewpoint-position.
        Returns:
            An integer representing the index the viewpoint is at.
        """
        return self._viewpoint 
[docs]    def setCursor(self, index):
        if self._indexToPos(index)[1] < 0:
            self.setViewpoint(index)
        elif self._indexToPos(index)[1] > self.rect.h:
            self.setViewpoint(index - (self.rect.h / self.font.get_linesize()))
        return super(Listbox, self).setCursor(index) 
[docs]    def setText(self, text):
        """
        Note: Any given text will be ignored; use insert or delete instead.
        inherit_doc::
        """
        return self 
[docs]    def getText(self):
        return "\n".join(map(str, self.list)) 
[docs]    def setList(self, list):
        """
        Set the widget' list-representation of its content.
        Args:
            list: A list with the content to set.
        Returns:
            Itsself (the widget) for convenience.
        """
        self._list = list
        self.markDirty()
        return self 
[docs]    def getList(self):
        """
        Return the widget' list-representation of its content.
        Returns:
            A list representing the content of the widget.
        """
        return self._list 
[docs]    def insert(self, index, text):
        """
        Note: The argument 'text' can be of any type, not only a string.
        inherit_doc::
        """
        index = self.getActualIndex(index)
        self._list.append(text)
        self.markDirty() 
[docs]    def delete(self, start, end):
        start, end = self._sort(start, end)
        del self._list[start:end]
        self.markDirty() 
[docs]    def getActualIndex(self, index, constrain=True):
        if index == END:
            return len(self._list)
        if index == VIEWPOINT:
            return self._viewpoint
        return super(Listbox, self).getActualIndex(index, constrain) 
    def _indexToPos(self, index):
        return 0, self.font.get_linesize() * (index - self._viewpoint)
    def _posToIndex(self, x, y):
        return (y / self.font.get_linesize()) + self._viewpoint
[docs]    def update(self, *args):
        """
        Additionally handles keyboard-input.
        inherit_doc::
        """
        if len(args) > 0 and self.isActive() and self.isFocused():
            event = args[0]
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    self.moveCursor(-1)
                elif event.key == pygame.K_DOWN:
                    self.moveCursor(1)
            elif event.type == pygame.MOUSEBUTTONUP:
                if event.button == 4:
                    self.moveViewpoint(-1)
                elif event.button == 5:
                    self.moveViewpoint(1)
        super(Listbox, self).update(*args) 
    def _getAppearance(self, *args):
        """
        Additionally renders the listbox's list and selection.
        inherit_doc::
        """
        surface = super(Listbox, self)._getAppearance(*args)
        linesize = self.font.get_linesize()
        for n in range(self._viewpoint, len(self._list)):
            surface.blit(self._render(str(self._list[n])), (0, linesize * (n - self._viewpoint)))
        if self.isFocused():
            s, e = self._sort(CURSOR, SELECTION)
            for n in range(s, e + 1):
                selection = pygame.Surface((self.bounds.width, linesize), pygame.SRCALPHA, 32)
                selection.fill(self.selection_overlay)
                surface.blit(selection, (0, linesize * (n - self._viewpoint)))
        return surface
    list = property(getList, setList, doc="""The widget' list-representation of its content.""")
    viewpoint = property(getViewpoint, setViewpoint, doc="""The widget's position of the viewpoint as a index. This is the first currently visible index.""") 
# inherit docs from superclass
Listbox = inherit_docstrings_from_superclass(Listbox)