[kivy] Is there a way to collapse all the tabs in an Accordion?

全部を閉じれないアコーディオンの方が普通なのかな?

アコーディオンしかやりたいことに近いものがなかったんである。説明しずらいな…、絵としてこういうこと:

これまであんまし GUI 作ってこなかったヒトなんで、この kivy Accordion の振る舞いが普通なのかどうかはわからないんだけれど、とにかくこやつは必ず一つは collapse=False になる。つまり一つは必ず開いてしまう。一個しかアイテムのないアコーディオンなんてなんに使うんだ、てのは、アタシのキャプチャからわかってくれると思う。きっと本来はアコーディオンのテリトリーじゃないんだろうとは思うんだけれど、ほかに相応しいのがないのよね。

答えはここに。

ちょっとばかし気持ち悪い派生なんだけれど、一応こんなんで目的の「全閉じ可能なアコーディオン」:

my_accordion.py
 1 __all__ = ('AllCollapsableAccordionItem', 'AllCollapsableAccordion')
 2 
 3 from kivy.logger import Logger
 4 from kivy.uix.accordion import AccordionException, AccordionItem, Accordion
 5 
 6 class AllCollapsableAccordionItem(AccordionItem):
 7 
 8     def __init__(self, **kwargs):
 9         super(AllCollapsableAccordionItem, self).__init__(**kwargs)
10 
11     def on_touch_down(self, touch):
12         if not self.collide_point(*touch.pos):
13             return
14         if self.disabled:
15             return True
16         if self.collapse:
17             self.collapse = False
18             return True
19         else:
20             if self.container_title.collide_point(*touch.pos):
21                 self.collapse = True
22             else:
23                 self.collapse = False
24             return super(AccordionItem, self).on_touch_down(touch)
25 
26 
27 class AllCollapsableAccordion(Accordion):
28 
29     def __init__(self, **kwargs):
30         super(AllCollapsableAccordion, self).__init__(**kwargs)
31 
32     def _do_layout(self, dt):
33         children = self.children
34         if children:
35             all_collapsed = all(x.collapse for x in children)
36         else:
37             all_collapsed = False
38 
39         if all_collapsed:
40             children[0].collapse = True
41 
42         orientation = self.orientation
43         min_space = self.min_space
44         min_space_total = len(children) * self.min_space
45         w, h = self.size
46         x, y = self.pos
47         if orientation == 'horizontal':
48             display_space = self.width - min_space_total
49         else:
50             display_space = self.height - min_space_total
51 
52         if display_space <= 0:
53             Logger.warning('Accordion: not enough space '
54                            'for displaying all children')
55             Logger.warning('Accordion: need %dpx, got %dpx' % (
56                 min_space_total, min_space_total + display_space))
57             Logger.warning('Accordion: layout aborted.')
58             return
59 
60         if orientation == 'horizontal':
61             children = reversed(children)
62 
63         for child in children:
64             child_space = min_space
65             child_space += display_space * (1 - child.collapse_alpha)
66             child._min_space = min_space
67             child.x = x
68             child.y = y
69             child.orientation = self.orientation
70             if orientation == 'horizontal':
71                 child.content_size = display_space, h
72                 child.width = child_space
73                 child.height = h
74                 x += child_space
75             else:
76                 child.content_size = w, display_space
77                 child.width = w
78                 child.height = child_space
79                 y += child_space

あとは普通に kivy.uix.accordion.Accordionkivy.uix.accordion.AccordionItem を使うのと同じノリで:

main.py (抜粋)
 1 from my_accordion import (
 2     AllCollapsableAccordion, AllCollapsableAccordionItem)
 3 
 4 kv = '''
 5 #(...snip...)
 6 
 7     AllCollapsableAccordion:
 8         id: extra
 9         orientation: 'vertical'
10 
11         AllCollapsableAccordionItem:
12             collapse: True
13             title: 'Magnetic Declination Config'
14 
15 #(...snip...)
16 '''
17 Builder.load_string(kv)