-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a table, moved when events are initialized
- Loading branch information
Showing
6 changed files
with
274 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import pytest | ||
from tklife.arrange import Autogrid | ||
|
||
def test_grid_one_size_more_at_end(): | ||
""" | ||
""" | ||
expected = ( | ||
(0, 0), | ||
(1, 0), | ||
(0, 1), | ||
(1, 1), | ||
(0, 2), | ||
(1, 2), | ||
) | ||
actual=Autogrid((1,)).grid_tuples(6) | ||
assert tuple(actual) == expected | ||
|
||
def test_grid_two_size(): | ||
""" | ||
""" | ||
expected = ( | ||
(0, 0), (1, 0), (2, 0), (3, 0), | ||
(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), | ||
) | ||
actual=Autogrid((2,3)).grid_tuples(10) | ||
assert tuple(actual) == expected | ||
|
||
def test_grid_two_size_more_at_end(): | ||
""" | ||
""" | ||
expected = ( | ||
(0, 0), (1, 0), (2, 0), (3, 0), | ||
(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), | ||
(0, 2), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), | ||
) | ||
actual=Autogrid((2,3)).grid_tuples(16) | ||
assert tuple(actual) == expected | ||
|
||
def test_grid_three_size_more_at_end(): | ||
""" | ||
""" | ||
expected = ( | ||
(0, 0), (1, 0), (2, 0), (3, 0), | ||
(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), | ||
(0, 2), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), | ||
(0, 3), (1, 3), (2, 3), (3, 3), (4, 3), (5, 3), (6, 3), (7, 3) | ||
) | ||
actual= Autogrid((2,3,4)).grid_tuples(26) | ||
assert tuple(actual) == expected | ||
|
||
def test_grid_four_size_more_at_end(): | ||
""" | ||
""" | ||
expected = ( | ||
(0, 0), (1, 0), (2, 0), (3, 0), | ||
(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), | ||
(0, 2), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), | ||
(0, 3), (1, 3), (2, 3), (3, 3), | ||
(0, 4), (1, 4), (2, 4), (3, 4) | ||
) | ||
actual = Autogrid((2,3,4,2)).grid_tuples(26) | ||
assert tuple(actual) == expected | ||
|
||
def test_grid_dicts(): | ||
expected = ( | ||
{'a': 0, 'b':0}, {'a': 1, 'b':0}, | ||
{'a': 0, 'b':1}, {'a': 1, 'b':1}, | ||
) | ||
actual = Autogrid((1, )).grid_dicts(4, 'ab') | ||
assert tuple(actual) == expected | ||
|
||
def test_zip_dicts(): | ||
expected = ( | ||
('elema', {'a': 0, 'b':0}), ('elemb', {'a': 1, 'b':0}), | ||
('elemc', {'a': 0, 'b':1}), ('elemd', {'a': 1, 'b':1}), | ||
) | ||
actual = Autogrid((1, )).zip_dicts(('elema', 'elemb', 'elemc', 'elemd'), 'ab') | ||
assert tuple(actual) == expected |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
"""Module for gridding out lists of elements""" | ||
from math import floor | ||
from itertools import accumulate | ||
|
||
class Autogrid: | ||
""" | ||
Class for getting grid coordinates based on an enumeration | ||
""" | ||
|
||
def __init__(self, row_lengths, group_size=2): | ||
""" | ||
Sets the row lengths and group size for generators | ||
""" | ||
self.group_size = group_size | ||
self.__divisors = tuple( | ||
[length * group_size for length in row_lengths]) | ||
self.__row_boundaries = tuple(accumulate(self.__divisors)) | ||
|
||
def _get_row_index(self, index): | ||
"""Gets the row that the index is in""" | ||
for bound_index, boundary in enumerate(self.__row_boundaries): | ||
if index < boundary: | ||
return bound_index | ||
return len(self.__row_boundaries) - 1 | ||
|
||
def _get_divisor(self, index): | ||
return self.__divisors[self._get_row_index(index)] | ||
|
||
def _get_x_offset(self, index): | ||
row_index = self._get_row_index(index) | ||
first = self.__row_boundaries[row_index] | ||
return first % self._get_divisor(index) | ||
|
||
def _get_y_offset(self, index): | ||
row_index = self._get_row_index(index) | ||
last = self.__row_boundaries[row_index] | ||
if index < last: | ||
return 0 | ||
return floor((index - last) / self._get_divisor(index)) + 1 | ||
|
||
def grid_tuples(self, element_count): | ||
"""Yield grid coordinates as a 2-tuples (x, y)""" | ||
for index in range(element_count): | ||
items_per_row = self._get_divisor(index) | ||
x_val = (index - self._get_x_offset(index)) % items_per_row | ||
y_val = self._get_row_index(index) + self._get_y_offset(index) | ||
yield (x_val, y_val) | ||
|
||
def grid_dicts(self, element_count, keynames): | ||
"""Yields grid coordinates as a dict using keynames as keys""" | ||
if len(tuple(iter(keynames))) != self.group_size: | ||
raise ValueError("'colnames' must be of length %s" % | ||
(self.group_size)) | ||
return ( | ||
dict(zip(iter(keynames), coords)) | ||
for coords in self.grid_tuples(element_count) | ||
) | ||
|
||
def zip_dicts(self, elements, keynames): | ||
length = len(elements) | ||
return ( | ||
zip(elements, self.grid_dicts(length, keynames)) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
"""Creates some common widgets""" | ||
from tkinter import Text, Canvas, X, VERTICAL, HORIZONTAL, LEFT, BOTTOM, RIGHT, Y, BOTH, END | ||
from tkinter.ttk import Frame, Button, Scrollbar | ||
from tklife import CommonFrame | ||
|
||
|
||
class Table(CommonFrame): | ||
sort_up = " ▲" | ||
sort_down = " ▼" | ||
col_pack_options = { | ||
'fill': X, | ||
'expand': True | ||
} | ||
|
||
def __init__(self, column_headers, data, **kwargs): | ||
""" | ||
Creates a table | ||
""" | ||
self.column_headers = column_headers | ||
self.data = data | ||
super().__init__(**kwargs) | ||
|
||
def _create_events(self): | ||
"""Create events""" | ||
self.scrollable_canvas.bind( | ||
"<Configure>", | ||
lambda e: self.scrollable_canvas.configure( | ||
scrollregion=self.scrollable_canvas.bbox("all") | ||
) | ||
) | ||
|
||
def _create_vars(self): | ||
"""Create widget variables""" | ||
|
||
def _create_widgets(self): | ||
"""Create widgets""" | ||
self.table_frame = Frame(self) | ||
self.scrollable_canvas = Canvas(self.table_frame) | ||
self.x_scroll = Scrollbar( | ||
self, orient=HORIZONTAL, command=self.scrollable_canvas.xview) | ||
self.y_scroll = Scrollbar( | ||
self.table_frame, orient=VERTICAL, command=self.scrollable_canvas.yview) | ||
self.scrollable_canvas.configure(yscrollcommand=self.y_scroll.set, | ||
xscrollcommand=self.x_scroll.set) | ||
self.table = Frame(self.scrollable_canvas) | ||
for header_text in self.column_headers: | ||
widget = Frame(self.table) | ||
button = Button(widget, text=header_text) | ||
button.configure( | ||
command=lambda button=button: self._sort_command(button)) | ||
|
||
self._create_data_widgets() | ||
|
||
def _create_data_widgets(self): | ||
for row in self.data: | ||
for x_index, col_frame in enumerate(self.table.children.values()): | ||
widget = Text(col_frame, width=20, height=1) | ||
widget.insert('1.0', row[x_index]) | ||
|
||
def _layout_widgets(self): | ||
"""Layout widgets""" | ||
for col_frame in self.table.children.values(): | ||
for widget in col_frame.children.values(): | ||
widget.pack(**self.col_pack_options) | ||
col_frame.pack(side=LEFT, fill=X, expand=True) | ||
self.x_scroll.pack(side=BOTTOM, fill=X) | ||
self.y_scroll.pack(side=RIGHT, fill=Y) | ||
self.scrollable_canvas.pack(expand=True, fill=BOTH) | ||
self.scrollable_canvas.create_window( | ||
(0, 0), window=self.table, anchor="nw") | ||
self.table_frame.pack(expand=True, fill=BOTH) | ||
|
||
def _sort_command(self, button): | ||
"""Event that sorts by the element""" | ||
self.__reset_button_sort_text(except_button=button) | ||
if self.sort_up in button['text']: | ||
button.configure(text=button['text'][:-2] + self.sort_down) | ||
elif self.sort_down in button['text']: | ||
button.configure(text=button['text'][:-2] + self.sort_up) | ||
else: | ||
button.configure(text=button['text'] + self.sort_up) | ||
column_data = [ | ||
tuple(enumerate(column.pack_slaves())) for column in self.table.children.values() | ||
] | ||
column_to_sort_by = [col for col in column_data if col[0][1] == button][0] | ||
sort_kwargs = { | ||
'key': self.__sort_key | ||
} | ||
if self.sort_down in button['text']: | ||
sort_kwargs['reverse'] = True | ||
sorted_column = sorted(column_to_sort_by[1:], **sort_kwargs) | ||
self.__apply_sorting(sorted_column, column_data) | ||
|
||
@staticmethod | ||
def __sort_key(row): | ||
text = row[1].get(1.0, END) | ||
try: | ||
return int(text) | ||
except ValueError: | ||
try: | ||
return float(text) | ||
except ValueError: | ||
return text | ||
|
||
def __apply_sorting(self, sorted_column, column_data): | ||
for col in self.table.children.values(): | ||
for widget in tuple(col.children.values())[1:]: | ||
widget.pack_forget() | ||
|
||
index_order = [col[0] for col in sorted_column] | ||
all_sorted_columns = [] | ||
for col in [data[1:] for data in column_data]: | ||
all_sorted_columns.append([]) | ||
for index in index_order: | ||
found = [t for t in col if t[0] == index][0] | ||
all_sorted_columns[-1].append(found) | ||
found[1].pack(**self.col_pack_options) | ||
self.scrollable_canvas.update_idletasks() | ||
|
||
def __reset_button_sort_text(self, except_button=None): | ||
for col_widget in self.table.children.values(): | ||
button = tuple(col_widget.children.values())[0] | ||
if button is not except_button: | ||
button.configure(text=button['text'].replace( | ||
self.sort_up, '').replace(self.sort_down, '')) |