Version

Quick search

Table Of Contents

Source code for kivy.uix.recycleboxlayout

"""
RecycleBoxLayout
================

.. versionadded:: 1.10.0

.. warning::
    This module is highly experimental, its API may change in the future and
    the documentation is not complete at this time.

The RecycleBoxLayout is designed to provide a
:class:`~kivy.uix.boxlayout.BoxLayout` type layout when used with the
:class:`~kivy.uix.recycleview.RecycleView` widget. Please refer to the
:mod:`~kivy.uix.recycleview` module documentation for more information.

"""

from kivy.uix.recyclelayout import RecycleLayout
from kivy.uix.boxlayout import BoxLayout

__all__ = ('RecycleBoxLayout', )


[docs]class RecycleBoxLayout(RecycleLayout, BoxLayout): _rv_positions = None def __init__(self, **kwargs): super(RecycleBoxLayout, self).__init__(**kwargs) self.funbind('children', self._trigger_layout) def _update_sizes(self, changed): horizontal = self.orientation == 'horizontal' padding_left, padding_top, padding_right, padding_bottom = self.padding padding_x = padding_left + padding_right padding_y = padding_top + padding_bottom selfw = self.width selfh = self.height layout_w = max(0, selfw - padding_x) layout_h = max(0, selfh - padding_y) cx = self.x + padding_left cy = self.y + padding_bottom view_opts = self.view_opts remove_view = self.remove_view for (index, widget, (w, h), (wn, hn), (shw, shh), (shnw, shnh), (shw_min, shh_min), (shwn_min, shhn_min), (shw_max, shh_max), (shwn_max, shhn_max), ph, phn) in changed: if (horizontal and (shw != shnw or w != wn or shw_min != shwn_min or shw_max != shwn_max) or not horizontal and (shh != shnh or h != hn or shh_min != shhn_min or shh_max != shhn_max)): return True remove_view(widget, index) opt = view_opts[index] if horizontal: wo, ho = opt['size'] if shnh is not None: _, h = opt['size'] = [wo, shnh * layout_h] else: h = ho xo, yo = opt['pos'] for key, value in phn.items(): posy = value * layout_h if key == 'y': yo = posy + cy elif key == 'top': yo = posy - h elif key == 'center_y': yo = posy - (h / 2.) opt['pos'] = [xo, yo] else: wo, ho = opt['size'] if shnw is not None: w, _ = opt['size'] = [shnw * layout_w, ho] else: w = wo xo, yo = opt['pos'] for key, value in phn.items(): posx = value * layout_w if key == 'x': xo = posx + cx elif key == 'right': xo = posx - w elif key == 'center_x': xo = posx - (w / 2.) opt['pos'] = [xo, yo] return False def compute_layout(self, data, flags): super(RecycleBoxLayout, self).compute_layout(data, flags) changed = self._changed_views if (changed is None or changed and not self._update_sizes(changed)): return self.clear_layout() self._rv_positions = None if not data: l, t, r, b = self.padding self.minimum_size = l + r, t + b return view_opts = self.view_opts n = len(view_opts) for i, x, y, w, h in self._iterate_layout( [(opt['size'], opt['size_hint'], opt['pos_hint'], opt['size_hint_min'], opt['size_hint_max']) for opt in reversed(view_opts)]): opt = view_opts[n - i - 1] shw, shh = opt['size_hint'] opt['pos'] = x, y wo, ho = opt['size'] # layout won't/shouldn't change previous size if size_hint is None # which is what w/h being None means. opt['size'] = [(wo if shw is None else w), (ho if shh is None else h)] spacing = self.spacing pos = self._rv_positions = [None, ] * len(data) if self.orientation == 'horizontal': pos[0] = self.x last = pos[0] + self.padding[0] + view_opts[0]['size'][0] + \ spacing / 2. for i, val in enumerate(view_opts[1:], 1): pos[i] = last last += val['size'][0] + spacing else: last = pos[-1] = \ self.y + self.height - self.padding[1] - \ view_opts[0]['size'][1] - spacing / 2. n = len(view_opts) for i, val in enumerate(view_opts[1:], 1): last -= spacing + val['size'][1] pos[n - 1 - i] = last
[docs] def get_view_index_at(self, pos): calc_pos = self._rv_positions if not calc_pos: return 0 x, y = pos if self.orientation == 'horizontal': if x >= calc_pos[-1] or len(calc_pos) == 1: return len(calc_pos) - 1 ix = 0 for val in calc_pos[1:]: if x < val: return ix ix += 1 else: if y >= calc_pos[-1] or len(calc_pos) == 1: return 0 iy = 0 for val in calc_pos[1:]: if y < val: return len(calc_pos) - iy - 1 iy += 1 assert False
[docs] def compute_visible_views(self, data, viewport): if self._rv_positions is None or not data: return [] x, y, w, h = viewport at_idx = self.get_view_index_at if self.orientation == 'horizontal': a, b = at_idx((x, y)), at_idx((x + w, y)) else: a, b = at_idx((x, y + h)), at_idx((x, y)) return list(range(a, b + 1))