1
from kivy.adapters.dictadapter import DictAdapter
2
from kivy.properties import NumericProperty, ListProperty, \
3
BooleanProperty, AliasProperty, ObjectProperty
4
from kivy.uix.boxlayout import BoxLayout
5
from kivy.uix.gridlayout import GridLayout
6
from kivy.uix.listview import ListView, ListItemButton
7
from kivy.uix.label import Label
8
from kivy.uix.button import Button
9
from kivy.uix.widget import Widget
12
class OpsDictAdapter(DictAdapter):
14
listview_id = NumericProperty(0)
15
owning_view = ObjectProperty(None)
17
def __init__(self, **kwargs):
18
self.listview_id = kwargs['listview_id']
19
super(OpsDictAdapter, self).__init__(**kwargs)
21
def on_selection_change(self, *args):
22
for i in range(len(self.selection)):
23
listview_selection_buttons[self.listview_id][i].text = \
24
self.selection[i].text
26
if self.listview_id is 0:
27
# Scroll to the most recently selected item.
28
if len(self.selection) > 0:
29
print('selection', self.selection)
30
self.owning_view.scroll_to(
31
index=self.sorted_keys.index(self.selection[-1].text))
33
elif self.listview_id is 1:
34
# Scroll to the selected item that is the minimum of a sort.
35
if len(self.selection) > 0:
36
self.owning_view.scroll_to(
37
index=self.sorted_keys.index(
38
sorted([sel.text for sel in self.selection])[0]))
40
elif self.listview_id is 2:
41
# Scroll to the selected item that is the maximum of a sort.
42
if len(self.selection) > 0:
43
self.owning_view.scroll_to(
44
index=self.sorted_keys.index(
45
sorted([sel.text for sel in self.selection])[-1]))
48
class SelectionMonitor(Widget):
50
def get_count_string(self):
51
return "Total sel: " + str(self.sel_count_0 +
59
def set_count_string(self, value):
60
self.count_string = value
62
sel_count_0 = NumericProperty(0)
63
sel_count_1 = NumericProperty(0)
64
sel_count_2 = NumericProperty(0)
65
sel_count_3 = NumericProperty(0)
66
sel_count_4 = NumericProperty(0)
67
sel_count_5 = NumericProperty(0)
68
sel_count_6 = NumericProperty(0)
70
count_string = AliasProperty(get_count_string,
80
def __init__(self, **kwargs):
81
super(SelectionMonitor, self).__init__(**kwargs)
83
def update_sel_count_0(self, adapter, *args):
84
self.sel_count_0 = len(adapter.selection)
86
def update_sel_count_1(self, adapter, *args):
87
self.sel_count_1 = len(adapter.selection)
89
def update_sel_count_2(self, adapter, *args):
90
self.sel_count_2 = len(adapter.selection)
92
def update_sel_count_3(self, adapter, *args):
93
self.sel_count_3 = len(adapter.selection)
95
def update_sel_count_4(self, adapter, *args):
96
self.sel_count_4 = len(adapter.selection)
98
def update_sel_count_5(self, adapter, *args):
99
self.sel_count_5 = len(adapter.selection)
101
def update_sel_count_6(self, adapter, *args):
102
self.sel_count_6 = len(adapter.selection)
106
{l: {'text': l, 'is_selected': False} for l in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'}
108
listview_selection_buttons = {}
111
class OpsView(BoxLayout):
112
'''Seven list views are shown at the bottom, each focusing on one of the
113
available operations for collection adapters: scroll_to, trim_to_sel,
114
trim_left_of_sel, etc. At the top is a display that shows individual
115
items selected across the seven lists, along with a total of all selected
118
def __init__(self, **kwargs):
119
kwargs['orientation'] = 'vertical'
120
super(OpsView, self).__init__(**kwargs)
124
# Create an upper panel with labels for items selected in the
125
# listviews shown in the lower panel.
127
upper_panel = BoxLayout()
129
grid_layout = GridLayout(cols=1,
130
row_force_default=True,
131
row_default_height=40)
133
# On the left side of the upper panel, show the selected items. There
134
# is a total possible of 5 for each listview, so 5 buttons are made.
136
for listview_id in range(7):
137
box_layout = BoxLayout()
138
listview_selection_buttons[listview_id] = []
140
box_layout.add_widget(
141
Label(text="Listview #{0} selection".format(listview_id)))
144
button = Button(size_hint_x=None, width=50,
145
size_hint_y=None, height=35,
146
background_color=[.25, .25, .6, 1.0])
147
listview_selection_buttons[listview_id].append(button)
148
box_layout.add_widget(button)
150
grid_layout.add_widget(box_layout)
152
upper_panel.add_widget(grid_layout)
154
# On the right side of the upper panel, show the total selected count.
156
total_selection_button = Button(text="Total: 0",
158
background_color=[.25, .25, .6, 1.0])
159
selection_monitor = SelectionMonitor()
160
selection_monitor.bind(
161
count_string=total_selection_button.setter('text'))
163
upper_panel.add_widget(total_selection_button)
165
self.add_widget(upper_panel)
169
# Show 6 listviews with either a header label or a header button.
171
grid_layout = GridLayout(cols=7)
173
list_item_args_converter = \
174
lambda row_index, rec: {'text': rec['text'],
178
letters = [l for l in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']
182
# Create 7 listviews, limiting selection to 5 items for the first 3,
183
# and allowing unlimited selection for the others, by setting the
184
# selection limit to 1000.
186
# Use OpsDictAdapter, from above, which will post selections to
187
# the display in the top panel.
189
listview_header_widgets = [Label(text="scroll_to rec",
192
Label(text="scroll_to min",
195
Label(text="scroll_to max",
198
Button(text="trim_left_of_sel",
201
Button(text="trim_right_of_sel",
204
Button(text="trim_to_sel",
207
Button(text="cut_to_sel",
211
for listview_id in range(7):
213
box_layout = BoxLayout(orientation='vertical')
215
letters_dict_adapter = \
217
listview_id=listview_id,
218
sorted_keys=letters[:],
220
args_converter=list_item_args_converter,
221
selection_mode='multiple',
222
selection_limit=5 if listview_id < 3 else 1000,
223
allow_empty_selection=True,
226
adapters.append(letters_dict_adapter)
228
letters_list_view = ListView(adapter=letters_dict_adapter)
230
letters_dict_adapter.owning_view = letters_list_view
232
box_layout.add_widget(listview_header_widgets[listview_id])
233
box_layout.add_widget(letters_list_view)
235
grid_layout.add_widget(box_layout)
237
# Bind selection of each list to the selection monitor.
238
adapters[0].bind(selection=selection_monitor.update_sel_count_0)
239
adapters[1].bind(selection=selection_monitor.update_sel_count_1)
240
adapters[2].bind(selection=selection_monitor.update_sel_count_2)
241
adapters[3].bind(selection=selection_monitor.update_sel_count_3)
242
adapters[4].bind(selection=selection_monitor.update_sel_count_4)
243
adapters[5].bind(selection=selection_monitor.update_sel_count_5)
244
adapters[6].bind(selection=selection_monitor.update_sel_count_6)
246
# For the last three listviews, bind the header buttons to the trim
247
# op method in the associated dict adapter instance.
248
button_3 = listview_header_widgets[3]
249
button_4 = listview_header_widgets[4]
250
button_5 = listview_header_widgets[5]
251
button_6 = listview_header_widgets[6]
252
button_3.bind(on_release=adapters[3].trim_left_of_sel)
253
button_4.bind(on_release=adapters[4].trim_right_of_sel)
254
button_5.bind(on_release=adapters[5].trim_to_sel)
255
button_6.bind(on_release=adapters[6].cut_to_sel)
257
self.add_widget(grid_layout)
260
if __name__ == '__main__':
261
from kivy.base import runTouchApp
262
runTouchApp(OpsView(width=800))