#
#		Python GUI - Views - Generic
#

from Properties import overridable_property
from Geometry import add_pt, sub_pt, rect_sized
from Containers import Container
from ViewBases import ViewBase

_default_line_scroll_amount = (16, 16)

class View(Container, ViewBase):
    """A View is a 2D drawing area having its own coordinate
    system and clipping area, with support for scrolling."""
    
    extent = overridable_property('extent',
        "Limits of scrollable area in local coordinates.")

    scroll_offset = overridable_property('scroll_offset',
        "Current scrolling position.")

    line_scroll_amount = overridable_property('line_scroll_amount',
        "Tuple specifying horizontal and vertical line scrolling increments.")

    scroll_bars = overridable_property('scroll_bars',
        "Attached ScrollBar instances.")

    #  _scroll_bars          [ScrollBar]

    #
    #		Construction and destruction
    #

    def __init__(self, **kwds):
        self._scroll_bars = []
        ViewBase.__init__(self)
        Container.__init__(self, **kwds)
    
    def destroy(self):
        ViewBase.destroy(self)
        Container.destroy(self)

    #
    #		Coordinate transformation
    #

    def local_to_container_offset(self):
        return sub_pt(self.position, self.scroll_offset)

    #
    #		Scrolling
    #

    def h_line_scroll_amount(self):
        """Return the horizontal line scroll increment."""
        return self.line_scroll_amount[0]

    def v_line_scroll_amount(self):
        """Return the vertical line scroll increment."""
        return self.line_scroll_amount[1]

    def h_page_scroll_amount(self):
        """Return the horizontal page scroll increment."""
        return self.width - self.h_line_scroll_amount()

    def v_page_scroll_amount(self):
        """Return the vertical page scroll increment."""
        return self.height - self.v_line_scroll_amount()

    def scroll_by(self, dx, dy):
        """Scroll by the given amount horizontally and vertically."""
        self.scroll_offset = add_pt(self.scroll_offset, (dx, dy))

    def scroll_line_left(self):
        """Called by horizontal scroll bar to scroll left by one line."""
        self.scroll_by(-self.h_line_scroll_amount(), 0)

    def scroll_line_right(self):
        """Called by horizontal scroll bar to scroll right by one line."""
        self.scroll_by(self.h_line_scroll_amount(), 0)

    def scroll_line_up(self):
        """Called by vertical scroll bar to scroll up by one line."""
        self.scroll_by(0, -self.v_line_scroll_amount())

    def scroll_line_down(self):
        """Called by vertical scroll bar to scroll down by one line."""
        self.scroll_by(0, self.v_line_scroll_amount())

    def scroll_page_left(self):
        """Called by horizontal scroll bar to scroll left by one page."""
        self.scroll_by(-self.h_page_scroll_amount(), 0)

    def scroll_page_right(self):
        """Called by horizontal scroll bar to scroll right by one page."""
        self.scroll_by(self.h_page_scroll_amount(), 0)

    def scroll_page_up(self):
        """Called by vertical scroll bar to scroll up by one page."""
        self.scroll_by(0, -self.v_page_scroll_amount())

    def scroll_page_down(self):
        """Called by vertical scroll bar to scroll down by one page."""
        self.scroll_by(0, self.v_page_scroll_amount())
    
    #
    #		Other methods
    #

    def viewed_rect(self):
        """Return the rectangle in local coordinates bounding the currently
        visible part of the extent."""
        return rect_sized(self.scroll_offset, self.size)
    
    def with_canvas(self, proc):
        """Call the procedure with a canvas suitable for drawing in this
        view. The canvas is only valid for the duration of the call, and
        should not be retained beyond it."""
        raise NotImplementedError

    #
    #		Callbacks
    #

    def draw(self, canvas):
        """Called when the component needs to be drawn."""
        pass

