Exemplo n.º 1
0
 def translate_opposite(self, delta):
     """ Returns a new Box that has the same size as this Box and a
     oppositely translated position as specified by delta.
     @param delta: The distance to the position of this Box, with opposite
     direction.
     @return: A new Box as specified above. """
     return Box(tools.vector_sub(self.get_position(), delta),
         self.get_size())
Exemplo n.º 2
0
 def translate_opposite(self, delta):
     """ Returns a new Box that has the same size as this Box and a
     oppositely translated position as specified by delta.
     @param delta: The distance to the position of this Box, with opposite
     direction.
     @return: A new Box as specified above. """
     return Box(tools.vector_sub(self.get_position(), delta),
                self.get_size())
Exemplo n.º 3
0
 def bounding_box(boxes):
     """ Returns the union of all specified Boxes (that is, the smallest Box
     that contains all specified Boxes).
     @param boxes: The Boxes to calculate the union from.
     @return: A Box as specified above. """
     if len(boxes) == 0:
         return Box((), ())
     mins = [None] * len(boxes[0].get_size())
     maxes = [None] * len(mins)
     for b in boxes:
         s = b.get_size()
         p = b.get_position()
         for i in range(len(mins)):
             if (mins[i] is None) or (p[i] < mins[i]):
                 mins[i] = p[i]
             ps = p[i] + s[i]
             if (maxes[i] is None) or (ps > maxes[i]):
                 maxes[i] = ps
     return Box(mins, tools.vector_sub(maxes, mins))
Exemplo n.º 4
0
 def bounding_box(boxes):
     """ Returns the union of all specified Boxes (that is, the smallest Box
     that contains all specified Boxes).
     @param boxes: The Boxes to calculate the union from.
     @return: A Box as specified above. """
     if len(boxes) == 0:
         return Box((), ())
     mins = [None] * len(boxes[0].get_size())
     maxes = [None] * len(mins)
     for b in boxes:
         s = b.get_size()
         p = b.get_position()
         for i in range(len(mins)):
             if (mins[i] is None) or (p[i] < mins[i]):
                 mins[i] = p[i]
             ps = p[i] + s[i]
             if (maxes[i] is None) or (ps > maxes[i]):
                 maxes[i] = ps
     return Box(mins, tools.vector_sub(maxes, mins))
Exemplo n.º 5
0
    def scroll_smartly(self, content_box, viewport_box, orientation, max_scroll,
                       axis_map=None):
        ''' Returns a new viewport position when reading forwards using
        the given orientation. If there is no space left to go, the empty
        list is returned. Note that all params are lists of ints (except
        max_scroll which might also contain floats) where each index
        corresponds to one dimension. The lower the index, the faster the
        corresponding position changes when reading. If you need to override
        this behavior, use the optional axis_map.
        @param content_box: The Box of the content to display.
        @param viewport_box: The viewport Box we are looking through.
        @param orientation: The orientation which shows where "forward"
        points to. Either 1 (towards larger values in this dimension when
        reading) or -1 (towards smaller values in this dimension when reading).
        Note that you can emulate "reading backwards" by flipping the sign
        of this argument.
        @param max_scroll: The maximum number of pixels to scroll in one step.
        (Floats allowed.)
        @param axis_map: The index of the dimension to modify.
        @return: A new viewport_position if you can read further or the
        empty list if there is nothing left to read. '''
        # Translate content and viewport so that content position equals origin
        offset = content_box.get_position()
        content_size = content_box.get_size()
        viewport_position = tools.vector_sub(viewport_box.get_position(), offset)
        viewport_size = viewport_box.get_size()
        # Remap axes
        if axis_map is not None:
            content_size, viewport_size, viewport_position, orientation, \
                max_scroll = Scrolling._map_remap_axes([content_size,
                viewport_size, viewport_position, orientation, max_scroll],
                axis_map)

        result = list(viewport_position)
        carry = True
        reset_all_axes = False
        for i in range(len(content_size)):
            invisible_size = content_size[i] - viewport_size[i]
            o = orientation[i]
            # Find a nice starting point
            if o == 1:
                if viewport_position[i] < 0:
                    result[i] = 0
                    carry = False
                    if viewport_position[i] <= -viewport_size[i]:
                        reset_all_axes = True
                        break
            else: # o == -1
                if viewport_position[i] > invisible_size:
                    result[i] = invisible_size
                    carry = False
                    if viewport_position[i] > content_size[i]:
                        reset_all_axes = True
                        break
        if reset_all_axes:
            # We don't see anything at all because we are somewhere way before
            # the content box. Let's go to it.
            for i in range(len(content_size)):
                invisible_size = content_size[i] - viewport_size[i]
                o = orientation[i]
                if o == 1:
                    result[i] = 0
                else: # o == -1
                    result[i] = invisible_size

        # This code is somewhat similar to a simple ripple-carry adder.
        if carry:
            for i in range(len(content_size)):
                invisible_size = content_size[i] - viewport_size[i]
                o = orientation[i]
                ms = min(max_scroll[i], invisible_size)
                # Let's calculate the grid we want to snap to.
                if ms != 0:
                    steps_to_take = int(math.ceil(float(invisible_size) / ms))
                if ms == 0 or steps_to_take >= invisible_size:
                    # special case: We MUST go forward by at least 1 pixel.
                    if o >= 0:
                        result[i] += 1
                        carry = result[i] > invisible_size
                        if carry:
                            result[i] = 0
                            continue
                    else:
                        result[i] -= 1
                        carry = result[i] < 0
                        if carry:
                            result[i] = invisible_size
                            continue
                    break
                # If orientation is -1, we need to round half up instead of
                # half down.
                positions = self._cached_bs(invisible_size, steps_to_take, o == -1)

                # Where are we now (according to the grid)?
                index = tools.bin_search(positions, viewport_position[i])

                if index < 0:
                    # We're somewhere between two valid grid points, so
                    # let's go to the next one.
                    index = ~index
                    if o >= 0:
                        # index tends to be greater, so we need to go back
                        # manually, if needed.
                        index -= 1
                # Let's go to where we're headed for.
                index += o

                carry = index < 0 or index >= len(positions)
                if carry:
                    # There is no space left in this dimension, so let's go
                    # back in this one and one step forward in the next one.
                    result[i] = 0 if o > 0 else invisible_size
                else:
                    # We found a valid grid point in this dimension, so let's
                    # stop here.
                    result[i] = positions[index]
                    break
        if carry:
            # No space left.
            return []

        # Undo axis remapping, if any
        if axis_map is not None:
            result = Scrolling._remap_axes(result,
                Scrolling._inverse_axis_map(axis_map))

        return tools.vector_add(result, offset)
Exemplo n.º 6
0
    def scroll_smartly(self, content_box, viewport_box, orientation, max_scroll,
        axis_map=None):
        """ Returns a new viewport position when reading forwards using
        the given orientation. If there is no space left to go, the empty
        list is returned. Note that all params are lists of ints (except
        max_scroll which might also contain floats) where each index
        corresponds to one dimension. The lower the index, the faster the
        corresponding position changes when reading. If you need to override
        this behavior, use the optional axis_map.
        @param content_box: The Box of the content to display.
        @param viewport_box: The viewport Box we are looking through.
        @param orientation: The orientation which shows where "forward"
        points to. Either 1 (towards larger values in this dimension when
        reading) or -1 (towards smaller values in this dimension when reading).
        Note that you can emulate "reading backwards" by flipping the sign
        of this argument.
        @param max_scroll: The maximum number of pixels to scroll in one step.
        (Floats allowed.)
        @param axis_map: The index of the dimension to modify.
        @return: A new viewport_position if you can read further or the
        empty list if there is nothing left to read. """
        # Translate content and viewport so that content position equals origin
        offset = content_box.get_position()
        content_size = content_box.get_size()
        viewport_position = tools.vector_sub(viewport_box.get_position(), offset)
        viewport_size = viewport_box.get_size()
        # Remap axes
        if axis_map is not None:
            content_size, viewport_size, viewport_position, orientation, \
                max_scroll = Scrolling._map_remap_axes([content_size,
                viewport_size, viewport_position, orientation, max_scroll],
                axis_map)

        result = list(viewport_position)
        carry = True
        reset_all_axes = False
        for i in range(len(content_size)):
            invisible_size = content_size[i] - viewport_size[i]
            o = orientation[i]
            # Find a nice starting point
            if o == 1:
                if viewport_position[i] < 0:
                    result[i] = 0
                    carry = False
                    if viewport_position[i] <= -viewport_size[i]:
                        reset_all_axes = True
                        break
            else: # o == -1
                if viewport_position[i] > invisible_size:
                    result[i] = invisible_size
                    carry = False
                    if viewport_position[i] > content_size[i]:
                        reset_all_axes = True
                        break
        if reset_all_axes:
            # We don't see anything at all because we are somewhere way before
            # the content box. Let's go to it.
            for i in range(len(content_size)):
                invisible_size = content_size[i] - viewport_size[i]
                o = orientation[i]
                if o == 1:
                    result[i] = 0
                else: # o == -1
                    result[i] = invisible_size

        # This code is somewhat similar to a simple ripple-carry adder.
        if carry:
            for i in range(len(content_size)):
                invisible_size = content_size[i] - viewport_size[i]
                o = orientation[i]
                ms = min(max_scroll[i], invisible_size)
                # Let's calculate the grid we want to snap to.
                if ms != 0:
                    steps_to_take = int(math.ceil(float(invisible_size) / ms))
                if ms == 0 or steps_to_take >= invisible_size:
                    # special case: We MUST go forward by at least 1 pixel.
                    if o >= 0:
                        result[i] += 1
                        carry = result[i] > invisible_size
                        if carry:
                            result[i] = 0
                            continue
                    else:
                        result[i] -= 1
                        carry = result[i] < 0
                        if carry:
                            result[i] = invisible_size
                            continue
                    break
                # If orientation is -1, we need to round half up instead of
                # half down.
                positions = self._cached_bs(invisible_size, steps_to_take, o == -1)

                # Where are we now (according to the grid)?
                index = tools.bin_search(positions, viewport_position[i])

                if index < 0:
                    # We're somewhere between two valid grid points, so
                    # let's go to the next one.
                    index = ~index
                    if o >= 0:
                        # index tends to be greater, so we need to go back
                        # manually, if needed.
                        index -= 1
                # Let's go to where we're headed for.
                index += o

                carry = index < 0 or index >= len(positions)
                if carry:
                    # There is no space left in this dimension, so let's go
                    # back in this one and one step forward in the next one.
                    result[i] = 0 if o > 0 else invisible_size
                else:
                    # We found a valid grid point in this dimension, so let's
                    # stop here.
                    result[i] = positions[index]
                    break
        if carry:
            # No space left.
            return []

        # Undo axis remapping, if any
        if axis_map is not None:
            result = Scrolling._remap_axes(result,
                Scrolling._inverse_axis_map(axis_map))

        return tools.vector_add(result, offset)