Advertisement
FoxboyPrower

adaptive_grid_layout fixed

Aug 11th, 2019
575
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.28 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. from collections import OrderedDict
  4. from kivy.uix.gridlayout import GridLayout
  5. from kivy.clock import Clock
  6.  
  7.  
  8. class Adaptive_GridLayout(GridLayout):
  9.     """
  10.    Adaptive height and row heights for grid layouts.
  11.  
  12.    Note this should not be used as a root layout and '_refresh_y_dimension()' method should be used by
  13.    children widgets that change height to update all attached instances of Adaptive_GridLayout (this layout).
  14.  
  15.    Copyright AGPL-3.0 2019 S0AndS0
  16.    """
  17.  
  18.     def __init__(self, grow_cols = False, grow_rows = False, **kwargs):
  19.         self.c_debug = False
  20.         if self.c_debug: print("Adaptive_GridLayout.__init__():", self)
  21.         super(Adaptive_GridLayout, self).__init__(**kwargs)
  22.         self.grow_cols = grow_cols
  23.         self.grow_rows = grow_rows
  24.         self.size_hint_y = None
  25.         self.trigger_refresh_y_dimension = Clock.create_trigger(lambda _: self._refresh_y_dimension(), 0)
  26.  
  27.     def _yield_tallest_of_each_row(self):
  28.         """ Yields tallest child of each row within gridlayout. """
  29.         if self.c_debug: print("\t\t\t\tAdaptive_GridLayout._yield_tallest_of_each_row():", self)
  30.         current_tallest = None
  31.         for i, c in enumerate(list(reversed(self.children))):
  32.             if current_tallest is None:
  33.                 current_tallest = c
  34.  
  35.             if c.height > current_tallest.height:
  36.                 current_tallest = c
  37.  
  38.             ## Should work around grids without value for 'cols'
  39.             if self.cols is None or self.cols is 0:
  40.                 if self.c_debug: print("\t\t\t\t", current_tallest)
  41.                 yield current_tallest
  42.                 current_tallest = None
  43.             ## Reached last item of current row... Fizzbuzz!
  44.             elif ((i + 1) % self.cols == 0) is True:
  45.                 if self.c_debug: print("\t\t\t\t", current_tallest)
  46.                 yield current_tallest
  47.                 current_tallest = None
  48.  
  49.     def _calc_child_padding_y(self, child):
  50.         """ Returns total padding for a given child. """
  51.         if self.c_debug: print("\t\t\t\tAdaptive_GridLayout._calc_child_padding_y():", self, child)
  52.         ## May be faster than asking permission with an if statement as most widgets seem to have padding
  53.         try:
  54.             child_padding = child.padding
  55.         except AttributeError as e:
  56.             child_padding = [0]
  57.  
  58.         len_child_padding = len(child_padding)
  59.         if len_child_padding is 1:
  60.             padding = child_padding[0] * 2
  61.         elif len_child_padding is 2:
  62.             padding = child_padding[1] * 2
  63.         elif len_child_padding > 2:
  64.             padding = child_padding[1] + child_padding[3]
  65.         else:
  66.             padding = 0
  67.         if self.c_debug: print("\t\t\t\t", padding)
  68.         return padding
  69.  
  70.     def _calc_min_height(self):
  71.         """ Returns total height required to display tallest children of each row plus spacing between widgets. """
  72.         if self.c_debug: print("\t\t\tAdaptive_GridLayout._calc_min_height():", self)
  73.         min_height = 0
  74.         for c in self._yield_tallest_of_each_row():
  75.             min_height += c.height
  76.         if self.c_debug: print("\t\t\t", min_height)
  77.         return min_height
  78.  
  79.     def _calc_rows_minimum(self):
  80.         """ Returns ordered dictionary of how high each row should be to accommodate tallest children of each row. """
  81.         if self.c_debug: print("\t\t\tAdaptive_GridLayout._calc_rows_minimum():", self)
  82.         rows_minimum = OrderedDict()
  83.         for i, c in enumerate(self._yield_tallest_of_each_row()):
  84.             rows_minimum.update({i: c.height})
  85.         if self.c_debug: print("\t\t\t", rows_minimum)
  86.         return rows_minimum
  87.  
  88.     def _refresh_height(self):
  89.         """ Resets 'self.height' using value returned by '_calc_min_height' method. """
  90.         if self.c_debug: print("\t\tAdaptive_GridLayout._refresh_height():", self)
  91.         if self.c_debug: print("\t\tself.height before:", self.height)
  92.         self.height = self._calc_min_height()
  93.         if self.c_debug: print("\t\tself.height after:", self.height)
  94.  
  95.     def _refresh_rows_minimum(self):
  96.         """ Resets 'self.rows_minimum' using value returned by '_calc_rows_minimum' method. """
  97.         if self.c_debug: print("\t\tAdaptive_GridLayout._refresh_rows_minimum():", self)
  98.         if self.c_debug: print("\t\tself.rows_minimum before:", self.rows_minimum)
  99.         self.rows_minimum = self._calc_rows_minimum()
  100.         if self.c_debug: print("\t\tself.rows_minimum after:", self.rows_minimum)
  101.  
  102.     def _refresh_y_dimension(self):
  103.         """ Updates 'height' and 'rows_minimum' first for spawn, then for self, and finally for any progenitors. """
  104.         if self.c_debug: print("\tAdaptive_GridLayout._refresh_y_dimension():", self)
  105.         spawn = [x for x in self.walk(restrict = True) if hasattr(x, '_refresh_y_dimension') and x is not self]
  106.         for item in spawn:
  107.             item._refresh_rows_minimum()
  108.             item._refresh_height()
  109.  
  110.         self._refresh_rows_minimum()
  111.         self._refresh_height()
  112.  
  113.         progenitors = [x for x in self.walk_reverse() if hasattr(x, '_refresh_y_dimension') and x is not self]
  114.         for progenitor in progenitors:
  115.             progenitor._refresh_rows_minimum()
  116.             progenitor._refresh_height()
  117.  
  118.     def on_children(self, instance, value):
  119.         """ If 'grow_cols' or 'grow_rows' is True this will grow layout that way if needed instead of erroring out. """
  120.         if self.c_debug: print("Adaptive_GridLayout.on_children():", self, instance, value)
  121.         if not self.rows or not self.cols:
  122.             return super(Adaptive_GridLayout, self).on_children(instance, value)
  123.  
  124.         max_widgets = self.rows * self.cols
  125.         widget_count = len(value)
  126.  
  127.         differance = widget_count - max_widgets
  128.         if widget_count > max_widgets:
  129.             if self.grow_cols:
  130.                 self.cols += differance
  131.             elif self.grow_rows:
  132.                 self.rows += differance
  133.  
  134.         return super(Adaptive_GridLayout, self).on_children(instance, value)
  135.  
  136.     def on_parent(self, instance, value):
  137.         """ Some adjustments maybe needed to get top row behaving on all platforms. """
  138.         if self.c_debug: print("Adaptive_GridLayout.on_parent():", self, instance, value)
  139.         self.trigger_refresh_y_dimension()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement