tksheet 7.4.3__tar.gz → 7.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tksheet-7.4.3/tksheet.egg-info → tksheet-7.4.4}/PKG-INFO +1 -1
- {tksheet-7.4.3 → tksheet-7.4.4}/pyproject.toml +1 -1
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/__init__.py +2 -2
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/column_headers.py +21 -14
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/functions.py +26 -26
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/main_table.py +56 -44
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/row_index.py +39 -28
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/sheet.py +34 -47
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/sheet_options.py +2 -0
- tksheet-7.4.4/tksheet/sorting.py +531 -0
- {tksheet-7.4.3 → tksheet-7.4.4/tksheet.egg-info}/PKG-INFO +1 -1
- tksheet-7.4.3/tksheet/sorting.py +0 -318
- {tksheet-7.4.3 → tksheet-7.4.4}/LICENSE.txt +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/README.md +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/setup.cfg +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/colors.py +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/constants.py +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/find_window.py +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/formatters.py +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/other_classes.py +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/text_editor.py +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/themes.py +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/tksheet_types.py +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet/top_left_rectangle.py +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet.egg-info/SOURCES.txt +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet.egg-info/dependency_links.txt +0 -0
- {tksheet-7.4.3 → tksheet-7.4.4}/tksheet.egg-info/top_level.txt +0 -0
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
6
6
|
name = "tksheet"
|
7
7
|
description = "Tkinter table / sheet and treeview widget"
|
8
8
|
readme = "README.md"
|
9
|
-
version = "7.4.
|
9
|
+
version = "7.4.4"
|
10
10
|
authors = [{ name = "ragardner", email = "github@ragardner.simplelogin.com" }]
|
11
11
|
requires-python = ">=3.8"
|
12
12
|
license = {file = "LICENSE.txt"}
|
@@ -4,7 +4,7 @@
|
|
4
4
|
tksheet - A Python tkinter table widget
|
5
5
|
"""
|
6
6
|
|
7
|
-
__version__ = "7.4.
|
7
|
+
__version__ = "7.4.4"
|
8
8
|
|
9
9
|
from .colors import (
|
10
10
|
color_map,
|
@@ -93,7 +93,7 @@ from .other_classes import (
|
|
93
93
|
from .row_index import RowIndex
|
94
94
|
from .sheet import Dropdown, Sheet
|
95
95
|
from .sheet_options import new_sheet_options
|
96
|
-
from .sorting import natural_sort_key
|
96
|
+
from .sorting import fast_sort_key, natural_sort_key, version_sort_key
|
97
97
|
from .text_editor import (
|
98
98
|
TextEditor,
|
99
99
|
TextEditorTkText,
|
@@ -874,6 +874,8 @@ class ColumnHeaders(tk.Canvas):
|
|
874
874
|
columns = list(range(0, len(self.MT.col_positions) - 1))
|
875
875
|
event_data = self.MT.new_event_dict("edit_table")
|
876
876
|
try_binding(self.MT.extra_begin_sort_cells_func, event_data)
|
877
|
+
if key is None:
|
878
|
+
key = self.PAR.ops.sort_key
|
877
879
|
for c in columns:
|
878
880
|
datacn = self.MT.datacn(c)
|
879
881
|
for r, val in enumerate(
|
@@ -923,6 +925,8 @@ class ColumnHeaders(tk.Canvas):
|
|
923
925
|
return event_data
|
924
926
|
column = self.MT.selected.column
|
925
927
|
if try_binding(self.ch_extra_begin_sort_rows_func, event_data, "begin_move_rows"):
|
928
|
+
if key is None:
|
929
|
+
key = self.PAR.ops.sort_key
|
926
930
|
disp_new_idxs, disp_row_ctr = {}, 0
|
927
931
|
if self.ops.treeview:
|
928
932
|
new_nodes_order, data_new_idxs = sort_tree_view(
|
@@ -2239,16 +2243,17 @@ class ColumnHeaders(tk.Canvas):
|
|
2239
2243
|
self.MT._headers[datacn] = value
|
2240
2244
|
|
2241
2245
|
def input_valid_for_cell(self, datacn: int, value: object, check_readonly: bool = True) -> bool:
|
2242
|
-
|
2246
|
+
kwargs = self.get_cell_kwargs(datacn, key=None)
|
2247
|
+
if check_readonly and "readonly" in kwargs:
|
2243
2248
|
return False
|
2244
|
-
|
2249
|
+
elif "checkbox" in kwargs:
|
2245
2250
|
return is_bool_like(value)
|
2246
|
-
|
2251
|
+
elif self.cell_equal_to(datacn, value):
|
2247
2252
|
return False
|
2248
|
-
kwargs
|
2249
|
-
if kwargs and kwargs["validate_input"] and value not in kwargs["values"]:
|
2253
|
+
elif (kwargs := kwargs.get("dropdown", {})) and kwargs["validate_input"] and value not in kwargs["values"]:
|
2250
2254
|
return False
|
2251
|
-
|
2255
|
+
else:
|
2256
|
+
return True
|
2252
2257
|
|
2253
2258
|
def cell_equal_to(self, datacn: int, value: object) -> bool:
|
2254
2259
|
self.fix_header(datacn)
|
@@ -2303,12 +2308,13 @@ class ColumnHeaders(tk.Canvas):
|
|
2303
2308
|
return value
|
2304
2309
|
|
2305
2310
|
def get_value_for_empty_cell(self, datacn: int, c_ops: bool = True) -> object:
|
2306
|
-
|
2311
|
+
kwargs = self.get_cell_kwargs(datacn, key=None, cell=c_ops)
|
2312
|
+
if "checkbox" in kwargs:
|
2307
2313
|
return False
|
2308
|
-
kwargs
|
2309
|
-
if kwargs and kwargs["validate_input"] and kwargs["values"]:
|
2314
|
+
elif (kwargs := kwargs.get("dropdown", {})) and kwargs["validate_input"] and kwargs["values"]:
|
2310
2315
|
return kwargs["values"][0]
|
2311
|
-
|
2316
|
+
else:
|
2317
|
+
return ""
|
2312
2318
|
|
2313
2319
|
def get_empty_header_seq(self, end: int, start: int = 0, c_ops: bool = True) -> list[object]:
|
2314
2320
|
return [self.get_value_for_empty_cell(datacn, c_ops=c_ops) for datacn in range(start, end)]
|
@@ -2376,7 +2382,8 @@ class ColumnHeaders(tk.Canvas):
|
|
2376
2382
|
if redraw:
|
2377
2383
|
self.MT.refresh()
|
2378
2384
|
|
2379
|
-
def get_cell_kwargs(self, datacn: int, key: Hashable = "dropdown", cell: bool = True) -> dict:
|
2380
|
-
if cell and datacn in self.cell_options
|
2381
|
-
return self.cell_options[datacn][key
|
2382
|
-
|
2385
|
+
def get_cell_kwargs(self, datacn: int, key: Hashable | None = "dropdown", cell: bool = True) -> dict:
|
2386
|
+
if cell and datacn in self.cell_options:
|
2387
|
+
return self.cell_options[datacn] if key is None else self.cell_options[datacn].get(key, {})
|
2388
|
+
else:
|
2389
|
+
return {}
|
@@ -15,7 +15,7 @@ from typing import Literal
|
|
15
15
|
from .colors import color_map
|
16
16
|
from .constants import align_value_error, symbols_set
|
17
17
|
from .formatters import to_bool
|
18
|
-
from .other_classes import
|
18
|
+
from .other_classes import DotDict, EventDataDict, Highlight, Loc, Span
|
19
19
|
from .tksheet_types import AnyIter
|
20
20
|
|
21
21
|
unpickle_obj = pickle.loads
|
@@ -279,10 +279,6 @@ def float_to_int(f: int | float) -> int | float:
|
|
279
279
|
return int(f)
|
280
280
|
|
281
281
|
|
282
|
-
def selection_box_tup_to_dict(box: tuple) -> dict:
|
283
|
-
return {Box_nt(*box[:-1]): box[-1]}
|
284
|
-
|
285
|
-
|
286
282
|
def event_dict(
|
287
283
|
name: str = None,
|
288
284
|
sheet: object = None,
|
@@ -334,9 +330,7 @@ def event_dict(
|
|
334
330
|
),
|
335
331
|
named_spans=DotDict() if named_spans is None else named_spans,
|
336
332
|
options=DotDict(),
|
337
|
-
selection_boxes=
|
338
|
-
{} if boxes is None else selection_box_tup_to_dict(boxes) if isinstance(boxes, tuple) else boxes
|
339
|
-
),
|
333
|
+
selection_boxes={} if boxes is None else boxes,
|
340
334
|
selected=tuple() if selected is None else selected,
|
341
335
|
being_selected=tuple() if being_selected is None else being_selected,
|
342
336
|
data=[] if data is None else data,
|
@@ -753,6 +747,17 @@ def move_elements_by_mapping(
|
|
753
747
|
return [seq[old_idxs[i]] if i in old_idxs else next(remaining_values) for i in range(len(seq))]
|
754
748
|
|
755
749
|
|
750
|
+
def move_elements_by_mapping_gen(
|
751
|
+
seq: list[object],
|
752
|
+
new_idxs: dict[int, int],
|
753
|
+
old_idxs: dict[int, int] | None = None,
|
754
|
+
) -> Generator[object]:
|
755
|
+
if old_idxs is None:
|
756
|
+
old_idxs = dict(zip(new_idxs.values(), new_idxs))
|
757
|
+
remaining_values = (e for i, e in enumerate(seq) if i not in new_idxs)
|
758
|
+
return (seq[old_idxs[i]] if i in old_idxs else next(remaining_values) for i in range(len(seq)))
|
759
|
+
|
760
|
+
|
756
761
|
def move_elements_to(
|
757
762
|
seq: list[object],
|
758
763
|
move_to: int,
|
@@ -770,10 +775,12 @@ def move_elements_to(
|
|
770
775
|
|
771
776
|
def get_new_indexes(
|
772
777
|
move_to: int,
|
773
|
-
to_move:
|
778
|
+
to_move: AnyIter[int],
|
774
779
|
get_inverse: bool = False,
|
775
780
|
) -> tuple[dict]:
|
776
781
|
"""
|
782
|
+
move_to: A positive int, could possibly be the same as an element of to_move
|
783
|
+
to_move: A sorted list[int], ints always positive and unique, list never empty.
|
777
784
|
returns {old idx: new idx, ...}
|
778
785
|
"""
|
779
786
|
offset = sum(1 for i in to_move if i < move_to)
|
@@ -789,6 +796,11 @@ def insert_items(
|
|
789
796
|
to_insert: dict[int, object],
|
790
797
|
seq_len_func: Callable | None = None,
|
791
798
|
) -> list[object]:
|
799
|
+
"""
|
800
|
+
seq: list[object]
|
801
|
+
to_insert: keys are ints sorted in reverse, representing list indexes to insert items.
|
802
|
+
Values are any object, e.g. {1: 200, 0: 200}
|
803
|
+
"""
|
792
804
|
if to_insert:
|
793
805
|
if seq_len_func and next(iter(to_insert)) >= len(seq) + len(to_insert):
|
794
806
|
seq_len_func(next(iter(to_insert)) - len(to_insert))
|
@@ -876,24 +888,12 @@ def rounded_box_coords(
|
|
876
888
|
)
|
877
889
|
|
878
890
|
|
879
|
-
def diff_list(seq: list[float]) -> list[int]:
|
880
|
-
return [
|
881
|
-
int(b - a)
|
882
|
-
for a, b in zip(
|
883
|
-
seq,
|
884
|
-
islice(seq, 1, None),
|
885
|
-
)
|
886
|
-
]
|
887
|
-
|
888
|
-
|
889
891
|
def diff_gen(seq: list[float]) -> Generator[int]:
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
)
|
896
|
-
)
|
892
|
+
it = iter(seq)
|
893
|
+
a = next(it)
|
894
|
+
for b in it:
|
895
|
+
yield int(b - a)
|
896
|
+
a = b
|
897
897
|
|
898
898
|
|
899
899
|
def gen_coords(
|
@@ -50,7 +50,6 @@ from .functions import (
|
|
50
50
|
consecutive_ranges,
|
51
51
|
data_to_displayed_idxs,
|
52
52
|
diff_gen,
|
53
|
-
diff_list,
|
54
53
|
down_cell_within_box,
|
55
54
|
event_dict,
|
56
55
|
event_has_char_key,
|
@@ -72,6 +71,7 @@ from .functions import (
|
|
72
71
|
mod_span,
|
73
72
|
mod_span_widget,
|
74
73
|
move_elements_by_mapping,
|
74
|
+
move_elements_by_mapping_gen,
|
75
75
|
new_tk_event,
|
76
76
|
next_cell,
|
77
77
|
push_n,
|
@@ -932,19 +932,21 @@ class MainTable(tk.Canvas):
|
|
932
932
|
def sort_boxes(
|
933
933
|
self,
|
934
934
|
event: tk.Event | None = None,
|
935
|
-
boxes:
|
935
|
+
boxes: dict[tuple[int, int, int, int], Literal["cells", "rows", "columns"]] | None = None,
|
936
936
|
reverse: bool = False,
|
937
937
|
row_wise: bool = False,
|
938
938
|
validation: bool = True,
|
939
939
|
key: Callable | None = None,
|
940
940
|
undo: bool = True,
|
941
941
|
) -> EventDataDict:
|
942
|
-
if boxes
|
942
|
+
if not boxes:
|
943
943
|
boxes = self.get_boxes()
|
944
944
|
if not boxes:
|
945
|
-
boxes =
|
945
|
+
boxes = {Box_nt(0, 0, len(self.row_positions) - 1, len(self.col_positions) - 1): "cells"}
|
946
946
|
event_data = self.new_event_dict("edit_table", boxes=boxes)
|
947
947
|
try_binding(self.extra_begin_sort_cells_func, event_data)
|
948
|
+
if key is None:
|
949
|
+
key = self.PAR.ops.sort_key
|
948
950
|
for r1, c1, r2, c2 in boxes:
|
949
951
|
data = sort_selection(
|
950
952
|
[[self.get_cell_data(self.datarn(r), self.datacn(c)) for c in range(c1, c2)] for r in range(r1, r2)],
|
@@ -1287,26 +1289,36 @@ class MainTable(tk.Canvas):
|
|
1287
1289
|
data_indexes: bool = False,
|
1288
1290
|
) -> tuple[dict[int, int], dict[int, int], int, dict[int, int]]:
|
1289
1291
|
if not data_indexes or self.all_columns_displayed:
|
1290
|
-
disp_new_idxs = get_new_indexes(
|
1292
|
+
disp_new_idxs = get_new_indexes(
|
1293
|
+
move_to=move_to,
|
1294
|
+
to_move=to_move,
|
1295
|
+
)
|
1296
|
+
data_new_idxs = dict(disp_new_idxs)
|
1291
1297
|
else:
|
1292
1298
|
disp_new_idxs = {}
|
1299
|
+
data_new_idxs = get_new_indexes(
|
1300
|
+
move_to=move_to,
|
1301
|
+
to_move=to_move,
|
1302
|
+
)
|
1293
1303
|
# at_least_cols should not be len in this case as move_to can be len
|
1294
1304
|
fix_len = (move_to - 1) if move_to else move_to
|
1295
1305
|
if not self.all_columns_displayed and not data_indexes:
|
1296
1306
|
fix_len = self.datacn(fix_len)
|
1297
1307
|
totalcols = self.equalize_data_row_lengths(at_least_cols=fix_len)
|
1298
|
-
data_new_idxs = get_new_indexes(move_to=move_to, to_move=to_move)
|
1299
1308
|
if not self.all_columns_displayed and not data_indexes:
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1309
|
+
keep = set(map(self.datacn, to_move))
|
1310
|
+
data_new_idxs = {
|
1311
|
+
k: v
|
1312
|
+
for k, v in zip(
|
1313
|
+
move_elements_by_mapping_gen(
|
1303
1314
|
self.displayed_columns,
|
1304
1315
|
data_new_idxs,
|
1305
1316
|
dict(zip(data_new_idxs.values(), data_new_idxs)),
|
1306
1317
|
),
|
1307
1318
|
self.displayed_columns,
|
1308
|
-
)
|
1309
|
-
|
1319
|
+
)
|
1320
|
+
if k in keep
|
1321
|
+
}
|
1310
1322
|
return data_new_idxs, dict(zip(data_new_idxs.values(), data_new_idxs)), totalcols, disp_new_idxs
|
1311
1323
|
|
1312
1324
|
def move_columns_adjust_options_dict(
|
@@ -1338,7 +1350,7 @@ class MainTable(tk.Canvas):
|
|
1338
1350
|
|
1339
1351
|
if move_widths and disp_new_idxs:
|
1340
1352
|
self.set_col_positions(
|
1341
|
-
itr=
|
1353
|
+
itr=move_elements_by_mapping_gen(
|
1342
1354
|
self.get_column_widths(),
|
1343
1355
|
disp_new_idxs,
|
1344
1356
|
dict(
|
@@ -1537,7 +1549,7 @@ class MainTable(tk.Canvas):
|
|
1537
1549
|
data_new_idxs = {
|
1538
1550
|
k: v
|
1539
1551
|
for k, v in zip(
|
1540
|
-
|
1552
|
+
move_elements_by_mapping_gen(
|
1541
1553
|
self.displayed_rows,
|
1542
1554
|
data_new_idxs,
|
1543
1555
|
dict(zip(data_new_idxs.values(), data_new_idxs)),
|
@@ -1732,7 +1744,7 @@ class MainTable(tk.Canvas):
|
|
1732
1744
|
|
1733
1745
|
if move_heights and disp_new_idxs:
|
1734
1746
|
self.set_row_positions(
|
1735
|
-
itr=
|
1747
|
+
itr=move_elements_by_mapping_gen(
|
1736
1748
|
self.get_row_heights(),
|
1737
1749
|
disp_new_idxs,
|
1738
1750
|
dict(
|
@@ -1788,7 +1800,7 @@ class MainTable(tk.Canvas):
|
|
1788
1800
|
old_idxs = dict(zip(new_idxs.values(), new_idxs))
|
1789
1801
|
return dict(
|
1790
1802
|
zip(
|
1791
|
-
|
1803
|
+
move_elements_by_mapping_gen(tuple(range(max_idx + 1)), new_idxs, old_idxs),
|
1792
1804
|
range(max_idx + 1),
|
1793
1805
|
)
|
1794
1806
|
)
|
@@ -4489,10 +4501,10 @@ class MainTable(tk.Canvas):
|
|
4489
4501
|
self.set_row_positions(itr=(h for i, h in enumerate(self.gen_row_heights()) if i not in idxs))
|
4490
4502
|
|
4491
4503
|
def get_column_widths(self) -> list[int]:
|
4492
|
-
return
|
4504
|
+
return list(diff_gen(self.col_positions))
|
4493
4505
|
|
4494
4506
|
def get_row_heights(self) -> list[int]:
|
4495
|
-
return
|
4507
|
+
return list(diff_gen(self.row_positions))
|
4496
4508
|
|
4497
4509
|
def gen_column_widths(self) -> Generator[int]:
|
4498
4510
|
return diff_gen(self.col_positions)
|
@@ -7893,26 +7905,20 @@ class MainTable(tk.Canvas):
|
|
7893
7905
|
self.data[datarn][datacn] = value
|
7894
7906
|
|
7895
7907
|
def get_value_for_empty_cell(self, datarn: int, datacn: int, r_ops: bool = True, c_ops: bool = True) -> object:
|
7896
|
-
if self.get_cell_kwargs(
|
7897
|
-
datarn,
|
7898
|
-
datacn,
|
7899
|
-
key="checkbox",
|
7900
|
-
cell=r_ops and c_ops,
|
7901
|
-
row=r_ops,
|
7902
|
-
column=c_ops,
|
7903
|
-
):
|
7904
|
-
return False
|
7905
7908
|
kwargs = self.get_cell_kwargs(
|
7906
7909
|
datarn,
|
7907
7910
|
datacn,
|
7908
|
-
key=
|
7911
|
+
key=None,
|
7909
7912
|
cell=r_ops and c_ops,
|
7910
7913
|
row=r_ops,
|
7911
7914
|
column=c_ops,
|
7912
7915
|
)
|
7913
|
-
if
|
7916
|
+
if "checkbox" in kwargs:
|
7917
|
+
return False
|
7918
|
+
elif (kwargs := kwargs.get("dropdown", {})) and kwargs["validate_input"] and kwargs["values"]:
|
7914
7919
|
return kwargs["values"][0]
|
7915
|
-
|
7920
|
+
else:
|
7921
|
+
return ""
|
7916
7922
|
|
7917
7923
|
def get_empty_row_seq(
|
7918
7924
|
self,
|
@@ -8072,18 +8078,21 @@ class MainTable(tk.Canvas):
|
|
8072
8078
|
check_readonly: bool = True,
|
8073
8079
|
ignore_empty: bool = False,
|
8074
8080
|
) -> bool:
|
8075
|
-
|
8081
|
+
kwargs = self.get_cell_kwargs(datarn, datacn, key=None)
|
8082
|
+
if check_readonly and "readonly" in kwargs:
|
8076
8083
|
return False
|
8077
|
-
|
8084
|
+
elif "format" in kwargs:
|
8078
8085
|
return True
|
8079
|
-
|
8086
|
+
elif self.cell_equal_to(datarn, datacn, value, ignore_empty=ignore_empty):
|
8080
8087
|
return False
|
8081
|
-
|
8082
|
-
|
8088
|
+
elif (
|
8089
|
+
(dropdown := kwargs.get("dropdown", {})) and dropdown["validate_input"] and value not in dropdown["values"]
|
8090
|
+
):
|
8083
8091
|
return False
|
8084
|
-
|
8092
|
+
elif "checkbox" in kwargs:
|
8085
8093
|
return is_bool_like(value)
|
8086
|
-
|
8094
|
+
else:
|
8095
|
+
return True
|
8087
8096
|
|
8088
8097
|
def cell_equal_to(self, datarn: int, datacn: int, value: object, ignore_empty: bool = False, **kwargs) -> bool:
|
8089
8098
|
v = self.get_cell_data(datarn, datacn)
|
@@ -8118,18 +8127,21 @@ class MainTable(tk.Canvas):
|
|
8118
8127
|
self,
|
8119
8128
|
datarn: int,
|
8120
8129
|
datacn: int,
|
8121
|
-
key: Hashable = "format",
|
8130
|
+
key: Hashable | None = "format",
|
8122
8131
|
cell: bool = True,
|
8123
8132
|
row: bool = True,
|
8124
8133
|
column: bool = True,
|
8125
8134
|
) -> dict:
|
8126
|
-
if cell and (datarn, datacn) in self.cell_options
|
8127
|
-
return
|
8128
|
-
|
8129
|
-
|
8130
|
-
|
8131
|
-
return self.
|
8132
|
-
|
8135
|
+
if cell and (datarn, datacn) in self.cell_options:
|
8136
|
+
return (
|
8137
|
+
self.cell_options[(datarn, datacn)] if key is None else self.cell_options[(datarn, datacn)].get(key, {})
|
8138
|
+
)
|
8139
|
+
elif row and datarn in self.row_options:
|
8140
|
+
return self.row_options[datarn] if key is None else self.row_options[datarn].get(key, {})
|
8141
|
+
elif column and datacn in self.col_options:
|
8142
|
+
return self.col_options[datacn] if key is None else self.col_options[datacn].get(key, {})
|
8143
|
+
else:
|
8144
|
+
return {}
|
8133
8145
|
|
8134
8146
|
def datacn(self, c: int) -> int:
|
8135
8147
|
return c if self.all_columns_displayed else self.displayed_columns[c]
|
@@ -900,6 +900,8 @@ class RowIndex(tk.Canvas):
|
|
900
900
|
rows = list(range(0, len(self.MT.row_positions) - 1))
|
901
901
|
event_data = self.MT.new_event_dict("edit_table")
|
902
902
|
try_binding(self.MT.extra_begin_sort_cells_func, event_data)
|
903
|
+
if key is None:
|
904
|
+
key = self.PAR.ops.sort_key
|
903
905
|
for r in rows:
|
904
906
|
datarn = self.MT.datarn(r)
|
905
907
|
for c, val in enumerate(sort_row(self.MT.data[datarn], reverse=reverse, key=key)):
|
@@ -943,6 +945,8 @@ class RowIndex(tk.Canvas):
|
|
943
945
|
return event_data
|
944
946
|
row = self.MT.selected.row
|
945
947
|
if try_binding(self.ri_extra_begin_sort_cols_func, event_data, "begin_move_columns"):
|
948
|
+
if key is None:
|
949
|
+
key = self.PAR.ops.sort_key
|
946
950
|
sorted_indices, data_new_idxs = sort_columns_by_row(self.MT.data, row=row, reverse=reverse, key=key)
|
947
951
|
disp_new_idxs = {}
|
948
952
|
if self.MT.all_columns_displayed:
|
@@ -2424,16 +2428,17 @@ class RowIndex(tk.Canvas):
|
|
2424
2428
|
self.MT._row_index[datarn] = value
|
2425
2429
|
|
2426
2430
|
def input_valid_for_cell(self, datarn: int, value: object, check_readonly: bool = True) -> bool:
|
2427
|
-
|
2431
|
+
kwargs = self.get_cell_kwargs(datarn, key=None)
|
2432
|
+
if check_readonly and "readonly" in kwargs:
|
2428
2433
|
return False
|
2429
|
-
|
2434
|
+
elif "checkbox" in kwargs:
|
2430
2435
|
return is_bool_like(value)
|
2431
|
-
|
2436
|
+
elif self.cell_equal_to(datarn, value):
|
2432
2437
|
return False
|
2433
|
-
kwargs
|
2434
|
-
if kwargs and kwargs["validate_input"] and value not in kwargs["values"]:
|
2438
|
+
elif (kwargs := kwargs.get("dropdown", {})) and kwargs["validate_input"] and value not in kwargs["values"]:
|
2435
2439
|
return False
|
2436
|
-
|
2440
|
+
else:
|
2441
|
+
return True
|
2437
2442
|
|
2438
2443
|
def cell_equal_to(self, datarn: int, value: object) -> bool:
|
2439
2444
|
self.fix_index(datarn)
|
@@ -2495,12 +2500,13 @@ class RowIndex(tk.Canvas):
|
|
2495
2500
|
if self.ops.treeview:
|
2496
2501
|
iid = self.new_iid()
|
2497
2502
|
return Node(text=iid, iid=iid, parent=self.get_row_parent(datarn))
|
2498
|
-
|
2503
|
+
kwargs = self.get_cell_kwargs(datarn, key=None, cell=r_ops)
|
2504
|
+
if "checkbox" in kwargs:
|
2499
2505
|
return False
|
2500
|
-
kwargs
|
2501
|
-
if kwargs and kwargs["validate_input"] and kwargs["values"]:
|
2506
|
+
elif (kwargs := kwargs.get("dropdown", {})) and kwargs["validate_input"] and kwargs["values"]:
|
2502
2507
|
return kwargs["values"][0]
|
2503
|
-
|
2508
|
+
else:
|
2509
|
+
return ""
|
2504
2510
|
|
2505
2511
|
def get_empty_index_seq(self, end: int, start: int = 0, r_ops: bool = True) -> list[object]:
|
2506
2512
|
return [self.get_value_for_empty_cell(datarn, r_ops=r_ops) for datarn in range(start, end)]
|
@@ -2567,10 +2573,11 @@ class RowIndex(tk.Canvas):
|
|
2567
2573
|
if redraw:
|
2568
2574
|
self.MT.refresh()
|
2569
2575
|
|
2570
|
-
def get_cell_kwargs(self, datarn: int, key: Hashable = "dropdown", cell: bool = True) -> dict:
|
2571
|
-
if cell and datarn in self.cell_options
|
2572
|
-
return self.cell_options[datarn][key
|
2573
|
-
|
2576
|
+
def get_cell_kwargs(self, datarn: int, key: Hashable | None = "dropdown", cell: bool = True) -> dict:
|
2577
|
+
if cell and datarn in self.cell_options:
|
2578
|
+
return self.cell_options[datarn] if key is None else self.cell_options[datarn].get(key, {})
|
2579
|
+
else:
|
2580
|
+
return {}
|
2574
2581
|
|
2575
2582
|
# Treeview Mode
|
2576
2583
|
|
@@ -2671,25 +2678,33 @@ class RowIndex(tk.Canvas):
|
|
2671
2678
|
new_parent = node_change[1]
|
2672
2679
|
move_to_index = node_change[2]
|
2673
2680
|
if new_parent:
|
2674
|
-
move_to_index
|
2675
|
-
move_to_index
|
2676
|
-
|
2677
|
-
|
2678
|
-
|
2679
|
-
|
2681
|
+
if isinstance(move_to_index, int):
|
2682
|
+
move_to_index = min(move_to_index, len(self.tree[new_parent].children))
|
2683
|
+
else:
|
2684
|
+
move_to_index = len(self.tree[new_parent].children)
|
2685
|
+
move_to_row = self.tree_rns[new_parent]
|
2686
|
+
if new_parent == self.tree[item].parent:
|
2687
|
+
move_to_index += 1
|
2688
|
+
for i, ciid in enumerate(self.tree[new_parent].children):
|
2689
|
+
if i == move_to_index:
|
2690
|
+
break
|
2691
|
+
move_to_row += sum(1 for _ in self.get_iid_descendants(ciid)) + 1
|
2692
|
+
insert_row = move_to_row + 1
|
2680
2693
|
else:
|
2681
2694
|
num_top_nodes = sum(1 for _ in self.gen_top_nodes())
|
2682
2695
|
if move_to_index is None:
|
2683
2696
|
move_to_row = self.PAR.top_index_row(num_top_nodes - 1)
|
2684
2697
|
move_to_index = num_top_nodes
|
2698
|
+
insert_row = move_to_row
|
2685
2699
|
else:
|
2686
2700
|
move_to_row = self.PAR.top_index_row(move_to_index)
|
2701
|
+
insert_row = move_to_row
|
2687
2702
|
if move_to_row is None:
|
2688
2703
|
move_to_row = self.PAR.top_index_row(num_top_nodes - 1)
|
2689
2704
|
move_to_index = num_top_nodes
|
2705
|
+
insert_row = move_to_row + 1
|
2690
2706
|
|
2691
2707
|
move_to_iid = self.MT._row_index[move_to_row].iid
|
2692
|
-
insert_row = move_to_row + 1
|
2693
2708
|
disp_insert_row = None
|
2694
2709
|
|
2695
2710
|
else:
|
@@ -2733,10 +2748,10 @@ class RowIndex(tk.Canvas):
|
|
2733
2748
|
event_data["moved"]["rows"]["displayed"] = {}
|
2734
2749
|
if new_loc_is_displayed:
|
2735
2750
|
if disp_insert_row is None:
|
2736
|
-
if new_parent
|
2751
|
+
if new_parent or insert_row > move_to_row:
|
2737
2752
|
disp_insert_row = self.MT.disprn(self.tree_rns[move_to_iid]) + 1
|
2738
2753
|
else:
|
2739
|
-
disp_insert_row = self.MT.disprn(self.tree_rns[move_to_iid])
|
2754
|
+
disp_insert_row = self.MT.disprn(self.tree_rns[move_to_iid])
|
2740
2755
|
if (disp_from_row := self.MT.try_disprn(self.tree_rns[item])) is not None:
|
2741
2756
|
event_data["moved"]["rows"]["displayed"] = {disp_from_row: disp_insert_row}
|
2742
2757
|
else:
|
@@ -2756,7 +2771,6 @@ class RowIndex(tk.Canvas):
|
|
2756
2771
|
index=move_to_index,
|
2757
2772
|
)
|
2758
2773
|
move_to_index += 1
|
2759
|
-
|
2760
2774
|
event_data["moved"]["rows"]["data"] = get_new_indexes(
|
2761
2775
|
insert_row,
|
2762
2776
|
event_data["moved"]["rows"]["data"],
|
@@ -2782,7 +2796,6 @@ class RowIndex(tk.Canvas):
|
|
2782
2796
|
if not undo_modification and data_new_idxs:
|
2783
2797
|
if new_parent and (not self.PAR.item_displayed(new_parent) or new_parent not in self.tree_open_ids):
|
2784
2798
|
self.PAR.hide_rows(set(data_new_idxs.values()), data_indexes=True)
|
2785
|
-
|
2786
2799
|
if new_loc_is_displayed:
|
2787
2800
|
self.PAR.show_rows(
|
2788
2801
|
(r for r in data_new_idxs.values() if self.ancestors_all_open(self.MT._row_index[r].iid))
|
@@ -2959,9 +2972,7 @@ class RowIndex(tk.Canvas):
|
|
2959
2972
|
def move_pid_causes_recursive_loop(self, to_move_iid: str, move_to_parent: str) -> bool:
|
2960
2973
|
# if the parent the item is being moved under is one of the item's descendants
|
2961
2974
|
# then it is a recursive loop
|
2962
|
-
return
|
2963
|
-
move_to_parent == diid for diid in self.get_iid_descendants(to_move_iid)
|
2964
|
-
)
|
2975
|
+
return any(move_to_parent == diid for diid in self.get_iid_descendants(to_move_iid))
|
2965
2976
|
|
2966
2977
|
def tree_build(
|
2967
2978
|
self,
|