tksheet 7.3.4__py3-none-any.whl → 7.4.1__py3-none-any.whl
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/__init__.py +11 -11
- tksheet/column_headers.py +328 -239
- tksheet/constants.py +13 -0
- tksheet/functions.py +194 -11
- tksheet/main_table.py +957 -583
- tksheet/other_classes.py +12 -8
- tksheet/row_index.py +830 -259
- tksheet/sheet.py +465 -589
- tksheet/sheet_options.py +44 -1
- tksheet/sorting.py +287 -0
- tksheet/text_editor.py +2 -6
- tksheet/{types.py → tksheet_types.py} +10 -1
- {tksheet-7.3.4.dist-info → tksheet-7.4.1.dist-info}/METADATA +13 -16
- tksheet-7.4.1.dist-info/RECORD +22 -0
- tksheet-7.3.4.dist-info/RECORD +0 -21
- {tksheet-7.3.4.dist-info → tksheet-7.4.1.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.3.4.dist-info → tksheet-7.4.1.dist-info}/WHEEL +0 -0
- {tksheet-7.3.4.dist-info → tksheet-7.4.1.dist-info}/top_level.txt +0 -0
tksheet/sheet.py
CHANGED
@@ -2,9 +2,8 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import tkinter as tk
|
4
4
|
from bisect import bisect_left
|
5
|
-
from collections import
|
5
|
+
from collections import deque
|
6
6
|
from collections.abc import Callable, Generator, Hashable, Iterator, Sequence
|
7
|
-
from functools import partial
|
8
7
|
from itertools import accumulate, chain, filterfalse, islice, product, repeat
|
9
8
|
from operator import attrgetter
|
10
9
|
from timeit import default_timer
|
@@ -14,6 +13,7 @@ from typing import Literal
|
|
14
13
|
from .column_headers import ColumnHeaders
|
15
14
|
from .constants import (
|
16
15
|
USER_OS,
|
16
|
+
align_value_error,
|
17
17
|
backwards_compatibility_keys,
|
18
18
|
emitted_events,
|
19
19
|
named_span_types,
|
@@ -24,9 +24,9 @@ from .functions import (
|
|
24
24
|
add_highlight,
|
25
25
|
add_to_options,
|
26
26
|
alpha2idx,
|
27
|
+
bisect_in,
|
27
28
|
consecutive_ranges,
|
28
29
|
convert_align,
|
29
|
-
data_to_displayed_idxs,
|
30
30
|
del_from_options,
|
31
31
|
del_named_span_options,
|
32
32
|
del_named_span_options_nested,
|
@@ -66,9 +66,16 @@ from .other_classes import (
|
|
66
66
|
)
|
67
67
|
from .row_index import RowIndex
|
68
68
|
from .sheet_options import new_sheet_options
|
69
|
-
from .themes import
|
69
|
+
from .themes import (
|
70
|
+
theme_black,
|
71
|
+
theme_dark,
|
72
|
+
theme_dark_blue,
|
73
|
+
theme_dark_green,
|
74
|
+
theme_light_blue,
|
75
|
+
theme_light_green,
|
76
|
+
)
|
77
|
+
from .tksheet_types import AnyIter, CellPropertyKey, CreateSpanTypes
|
70
78
|
from .top_left_rectangle import TopLeftRectangle
|
71
|
-
from .types import AnyIter, CreateSpanTypes
|
72
79
|
|
73
80
|
|
74
81
|
class Sheet(tk.Frame):
|
@@ -77,7 +84,7 @@ class Sheet(tk.Frame):
|
|
77
84
|
parent: tk.Misc,
|
78
85
|
name: str = "!sheet",
|
79
86
|
show_table: bool = True,
|
80
|
-
show_top_left: bool =
|
87
|
+
show_top_left: bool = False,
|
81
88
|
show_row_index: bool = True,
|
82
89
|
show_header: bool = True,
|
83
90
|
show_x_scrollbar: bool = True,
|
@@ -110,10 +117,10 @@ class Sheet(tk.Frame):
|
|
110
117
|
after_redraw_time_ms: int = 20,
|
111
118
|
set_all_heights_and_widths: bool = False,
|
112
119
|
zoom: int = 100,
|
113
|
-
align: str = "
|
114
|
-
header_align: str = "
|
120
|
+
align: str = "nw",
|
121
|
+
header_align: str = "n",
|
115
122
|
row_index_align: str | None = None,
|
116
|
-
index_align: str = "
|
123
|
+
index_align: str = "n",
|
117
124
|
displayed_columns: list[int] = [],
|
118
125
|
all_columns_displayed: bool = True,
|
119
126
|
displayed_rows: list[int] = [],
|
@@ -172,9 +179,14 @@ class Sheet(tk.Frame):
|
|
172
179
|
edit_cell_return: Literal["right", "down", ""] = "down",
|
173
180
|
editor_del_key: Literal["forward", "backward", ""] = "forward",
|
174
181
|
treeview: bool = False,
|
175
|
-
treeview_indent: str | int = "
|
182
|
+
treeview_indent: str | int = "2",
|
176
183
|
rounded_boxes: bool = True,
|
177
184
|
alternate_color: str = "",
|
185
|
+
allow_cell_overflow: bool = False,
|
186
|
+
# "" no wrap, "w" word wrap, "c" char wrap
|
187
|
+
table_wrap: Literal["", "w", "c"] = "c",
|
188
|
+
index_wrap: Literal["", "w", "c"] = "c",
|
189
|
+
header_wrap: Literal["", "w", "c"] = "c",
|
178
190
|
# colors
|
179
191
|
outline_thickness: int = 0,
|
180
192
|
theme: str = "light blue",
|
@@ -329,22 +341,22 @@ class Sheet(tk.Frame):
|
|
329
341
|
self.config(width=350)
|
330
342
|
self.grid_columnconfigure(1, weight=1)
|
331
343
|
self.grid_rowconfigure(1, weight=1)
|
332
|
-
self.RI = RowIndex(
|
344
|
+
self.RI: RowIndex = RowIndex(
|
333
345
|
parent=self,
|
334
346
|
row_index_align=(
|
335
347
|
convert_align(row_index_align) if row_index_align is not None else convert_align(index_align)
|
336
348
|
),
|
337
349
|
)
|
338
|
-
self.CH = ColumnHeaders(
|
350
|
+
self.CH: ColumnHeaders = ColumnHeaders(
|
339
351
|
parent=self,
|
340
352
|
header_align=convert_align(header_align),
|
341
353
|
)
|
342
|
-
self.MT = MainTable(
|
354
|
+
self.MT: MainTable = MainTable(
|
343
355
|
parent=self,
|
344
|
-
show_index=show_row_index,
|
345
|
-
show_header=show_header,
|
346
356
|
column_headers_canvas=self.CH,
|
347
357
|
row_index_canvas=self.RI,
|
358
|
+
show_index=show_row_index,
|
359
|
+
show_header=show_header,
|
348
360
|
headers=headers,
|
349
361
|
header=header,
|
350
362
|
data_reference=data if data_reference is None else data_reference,
|
@@ -359,7 +371,7 @@ class Sheet(tk.Frame):
|
|
359
371
|
displayed_rows=displayed_rows,
|
360
372
|
all_rows_displayed=all_rows_displayed,
|
361
373
|
)
|
362
|
-
self.TL = TopLeftRectangle(
|
374
|
+
self.TL: TopLeftRectangle = TopLeftRectangle(
|
363
375
|
parent=self,
|
364
376
|
main_canvas=self.MT,
|
365
377
|
row_index_canvas=self.RI,
|
@@ -423,32 +435,19 @@ class Sheet(tk.Frame):
|
|
423
435
|
orient="horizontal",
|
424
436
|
style=f"Sheet{self.unique_id}.Horizontal.TScrollbar",
|
425
437
|
)
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
self.
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
self.
|
435
|
-
if
|
436
|
-
self.
|
437
|
-
|
438
|
-
|
439
|
-
self.xscroll.grid(row=2, column=0, columnspan=2, sticky="nswe")
|
440
|
-
self.xscroll_showing = True
|
441
|
-
self.xscroll_disabled = False
|
442
|
-
else:
|
443
|
-
self.xscroll_showing = False
|
444
|
-
self.xscroll_disabled = True
|
445
|
-
if show_y_scrollbar:
|
446
|
-
self.yscroll.grid(row=0, column=2, rowspan=3, sticky="nswe")
|
447
|
-
self.yscroll_showing = True
|
448
|
-
self.yscroll_disabled = False
|
449
|
-
else:
|
450
|
-
self.yscroll_showing = False
|
451
|
-
self.yscroll_disabled = True
|
438
|
+
self.show()
|
439
|
+
if not show_top_left and not (show_row_index and show_header):
|
440
|
+
self.hide("top_left")
|
441
|
+
if not show_row_index:
|
442
|
+
self.hide("row_index")
|
443
|
+
if not show_header:
|
444
|
+
self.hide("header")
|
445
|
+
if not show_table:
|
446
|
+
self.hide("table")
|
447
|
+
if not show_x_scrollbar:
|
448
|
+
self.hide("x_scrollbar")
|
449
|
+
if not show_y_scrollbar:
|
450
|
+
self.hide("y_scrollbar")
|
452
451
|
self.update_idletasks()
|
453
452
|
self.MT.update_idletasks()
|
454
453
|
self.RI.update_idletasks()
|
@@ -627,6 +626,11 @@ class Sheet(tk.Frame):
|
|
627
626
|
- "rc_delete_column"
|
628
627
|
- "rc_insert_row"
|
629
628
|
- "rc_delete_row"
|
629
|
+
- "sort_cells"
|
630
|
+
- "sort_row"
|
631
|
+
- "sort_column" / "sort_col"
|
632
|
+
- "sort_rows"
|
633
|
+
- "sort_columns" / "sort_cols"
|
630
634
|
- "ctrl_click_select" / "ctrl_select"
|
631
635
|
- "copy"
|
632
636
|
- "cut"
|
@@ -693,6 +697,12 @@ class Sheet(tk.Frame):
|
|
693
697
|
) -> Sheet:
|
694
698
|
"""
|
695
699
|
List of available bindings:
|
700
|
+
- "begin_sort_cells"
|
701
|
+
- "sort_cells", "end_sort_cells"
|
702
|
+
- "begin_sort_rows"
|
703
|
+
- "sort_rows", "end_sort_rows"
|
704
|
+
- "begin_sort_columns"
|
705
|
+
- "sort_columns", "end_sort_columns"
|
696
706
|
- "begin_copy", "begin_ctrl_c"
|
697
707
|
- "ctrl_c", "end_copy", "end_ctrl_c", "copy"
|
698
708
|
- "begin_cut", "begin_ctrl_x"
|
@@ -768,6 +778,9 @@ class Sheet(tk.Frame):
|
|
768
778
|
"bind_all",
|
769
779
|
"unbind_all",
|
770
780
|
):
|
781
|
+
self.MT.extra_begin_sort_cells_func = f
|
782
|
+
self.CH.ch_extra_begin_sort_rows_func = f
|
783
|
+
self.RI.ri_extra_begin_sort_cols_func = f
|
771
784
|
self.MT.extra_begin_ctrl_c_func = f
|
772
785
|
self.MT.extra_begin_ctrl_x_func = f
|
773
786
|
self.MT.extra_begin_ctrl_v_func = f
|
@@ -819,6 +832,9 @@ class Sheet(tk.Frame):
|
|
819
832
|
"modified_events",
|
820
833
|
"modified",
|
821
834
|
):
|
835
|
+
self.MT.extra_end_sort_cells_func = f
|
836
|
+
self.CH.ch_extra_end_sort_rows_func = f
|
837
|
+
self.RI.ri_extra_end_sort_cols_func = f
|
822
838
|
self.MT.extra_end_ctrl_c_func = f
|
823
839
|
self.MT.extra_end_ctrl_x_func = f
|
824
840
|
self.MT.extra_end_ctrl_v_func = f
|
@@ -834,6 +850,24 @@ class Sheet(tk.Frame):
|
|
834
850
|
self.CH.extra_end_edit_cell_func = f
|
835
851
|
self.RI.extra_end_edit_cell_func = f
|
836
852
|
|
853
|
+
if b in ("begin_sort_cells",):
|
854
|
+
self.MT.extra_begin_sort_cells_func = f
|
855
|
+
|
856
|
+
if b in ("sort_cells", "end_sort_cells"):
|
857
|
+
self.MT.extra_end_sort_cells_func = f
|
858
|
+
|
859
|
+
if b in ("begin_sort_rows",):
|
860
|
+
self.CH.ch_extra_begin_sort_rows_func = f
|
861
|
+
|
862
|
+
if b in ("sort_rows", "end_sort_rows"):
|
863
|
+
self.CH.ch_extra_end_sort_rows_func = f
|
864
|
+
|
865
|
+
if b in ("begin_sort_columns",):
|
866
|
+
self.RI.ri_extra_begin_sort_cols_func = f
|
867
|
+
|
868
|
+
if b in ("sort_columns", "end_sort_columns"):
|
869
|
+
self.RI.ri_extra_end_sort_cols_func = f
|
870
|
+
|
837
871
|
if b in (
|
838
872
|
"begin_copy",
|
839
873
|
"begin_ctrl_c",
|
@@ -1293,7 +1327,7 @@ class Sheet(tk.Frame):
|
|
1293
1327
|
transposed: bool = False,
|
1294
1328
|
ndim: int = 0,
|
1295
1329
|
convert: object = None,
|
1296
|
-
undo: bool =
|
1330
|
+
undo: bool = True,
|
1297
1331
|
emit_event: bool = False,
|
1298
1332
|
widget: object = None,
|
1299
1333
|
expand: None | str = None,
|
@@ -1765,8 +1799,6 @@ class Sheet(tk.Frame):
|
|
1765
1799
|
|
1766
1800
|
"""
|
1767
1801
|
span = self.span_from_key(*key)
|
1768
|
-
if data is None:
|
1769
|
-
data = []
|
1770
1802
|
startr, startc = span_froms(span)
|
1771
1803
|
table, index, header = span.table, span.index, span.header
|
1772
1804
|
fmt_kw = span.kwargs if span.type_ == "format" and span.kwargs else None
|
@@ -2072,7 +2104,7 @@ class Sheet(tk.Frame):
|
|
2072
2104
|
height: int | None = None,
|
2073
2105
|
row_index: bool = False,
|
2074
2106
|
fill: bool = True,
|
2075
|
-
undo: bool =
|
2107
|
+
undo: bool = True,
|
2076
2108
|
emit_event: bool = False,
|
2077
2109
|
redraw: bool = True,
|
2078
2110
|
) -> EventDataDict:
|
@@ -2094,7 +2126,7 @@ class Sheet(tk.Frame):
|
|
2094
2126
|
width: int | None = None,
|
2095
2127
|
header: bool = False,
|
2096
2128
|
fill: bool = True,
|
2097
|
-
undo: bool =
|
2129
|
+
undo: bool = True,
|
2098
2130
|
emit_event: bool = False,
|
2099
2131
|
redraw: bool = True,
|
2100
2132
|
) -> EventDataDict:
|
@@ -2116,11 +2148,12 @@ class Sheet(tk.Frame):
|
|
2116
2148
|
heights: list[int] | tuple[int] | None = None,
|
2117
2149
|
row_index: bool = False,
|
2118
2150
|
fill: bool = True,
|
2119
|
-
undo: bool =
|
2151
|
+
undo: bool = True,
|
2120
2152
|
emit_event: bool = False,
|
2121
2153
|
create_selections: bool = True,
|
2122
2154
|
add_column_widths: bool = True,
|
2123
2155
|
push_ops: bool = True,
|
2156
|
+
tree: bool = True,
|
2124
2157
|
redraw: bool = True,
|
2125
2158
|
) -> EventDataDict:
|
2126
2159
|
total_cols = None
|
@@ -2180,14 +2213,10 @@ class Sheet(tk.Frame):
|
|
2180
2213
|
row_index=row_index,
|
2181
2214
|
),
|
2182
2215
|
add_col_positions=add_column_widths,
|
2183
|
-
event_data=
|
2184
|
-
name="add_rows",
|
2185
|
-
sheet=self.name,
|
2186
|
-
boxes=self.MT.get_boxes(),
|
2187
|
-
selected=self.MT.selected,
|
2188
|
-
),
|
2216
|
+
event_data=self.MT.new_event_dict("add_rows", state=True),
|
2189
2217
|
create_selections=create_selections,
|
2190
2218
|
push_ops=push_ops,
|
2219
|
+
tree=tree,
|
2191
2220
|
)
|
2192
2221
|
if undo:
|
2193
2222
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2203,7 +2232,7 @@ class Sheet(tk.Frame):
|
|
2203
2232
|
widths: list[int] | tuple[int] | None = None,
|
2204
2233
|
headers: bool = False,
|
2205
2234
|
fill: bool = True,
|
2206
|
-
undo: bool =
|
2235
|
+
undo: bool = True,
|
2207
2236
|
emit_event: bool = False,
|
2208
2237
|
create_selections: bool = True,
|
2209
2238
|
add_row_heights: bool = True,
|
@@ -2275,12 +2304,7 @@ class Sheet(tk.Frame):
|
|
2275
2304
|
headers=headers,
|
2276
2305
|
),
|
2277
2306
|
add_row_positions=add_row_heights,
|
2278
|
-
event_data=
|
2279
|
-
name="add_columns",
|
2280
|
-
sheet=self.name,
|
2281
|
-
boxes=self.MT.get_boxes(),
|
2282
|
-
selected=self.MT.selected,
|
2283
|
-
),
|
2307
|
+
event_data=self.MT.new_event_dict("add_columns", state=True),
|
2284
2308
|
create_selections=create_selections,
|
2285
2309
|
push_ops=push_ops,
|
2286
2310
|
)
|
@@ -2291,124 +2315,48 @@ class Sheet(tk.Frame):
|
|
2291
2315
|
self.set_refresh_timer(redraw)
|
2292
2316
|
return event_data
|
2293
2317
|
|
2294
|
-
def
|
2295
|
-
self,
|
2296
|
-
idx: int = 0,
|
2297
|
-
data_indexes: bool = True,
|
2298
|
-
undo: bool = False,
|
2299
|
-
emit_event: bool = False,
|
2300
|
-
redraw: bool = True,
|
2301
|
-
) -> EventDataDict:
|
2302
|
-
return self.del_rows(
|
2303
|
-
rows=idx,
|
2304
|
-
data_indexes=data_indexes,
|
2305
|
-
undo=undo,
|
2306
|
-
emit_event=emit_event,
|
2307
|
-
redraw=redraw,
|
2308
|
-
)
|
2309
|
-
|
2310
|
-
delete_row = del_row
|
2311
|
-
|
2312
|
-
def del_column(
|
2318
|
+
def del_rows(
|
2313
2319
|
self,
|
2314
|
-
|
2320
|
+
rows: int | AnyIter[int],
|
2315
2321
|
data_indexes: bool = True,
|
2316
|
-
undo: bool =
|
2322
|
+
undo: bool = True,
|
2317
2323
|
emit_event: bool = False,
|
2318
2324
|
redraw: bool = True,
|
2319
2325
|
) -> EventDataDict:
|
2320
|
-
|
2321
|
-
|
2326
|
+
event_data = self.MT.delete_rows(
|
2327
|
+
rows=[rows] if isinstance(rows, int) else sorted(set(rows)),
|
2322
2328
|
data_indexes=data_indexes,
|
2323
2329
|
undo=undo,
|
2324
2330
|
emit_event=emit_event,
|
2325
|
-
|
2326
|
-
)
|
2327
|
-
|
2328
|
-
delete_column = del_column
|
2329
|
-
|
2330
|
-
def del_rows(
|
2331
|
-
self,
|
2332
|
-
rows: int | AnyIter[int],
|
2333
|
-
data_indexes: bool = True,
|
2334
|
-
undo: bool = False,
|
2335
|
-
emit_event: bool = False,
|
2336
|
-
redraw: bool = True,
|
2337
|
-
) -> EventDataDict:
|
2338
|
-
self.MT.deselect("all", redraw=False)
|
2339
|
-
rows = [rows] if isinstance(rows, int) else sorted(rows)
|
2340
|
-
event_data = event_dict(
|
2341
|
-
name="delete_rows",
|
2342
|
-
sheet=self.name,
|
2343
|
-
widget=self,
|
2344
|
-
boxes=self.MT.get_boxes(),
|
2345
|
-
selected=self.MT.selected,
|
2331
|
+
ext=True,
|
2346
2332
|
)
|
2347
|
-
if not data_indexes:
|
2348
|
-
event_data = self.MT.delete_rows_displayed(rows, event_data)
|
2349
|
-
event_data = self.MT.delete_rows_data(
|
2350
|
-
rows if self.MT.all_rows_displayed else [self.MT.displayed_rows[r] for r in rows],
|
2351
|
-
event_data,
|
2352
|
-
)
|
2353
|
-
else:
|
2354
|
-
if self.MT.all_rows_displayed:
|
2355
|
-
rows = rows
|
2356
|
-
else:
|
2357
|
-
rows = data_to_displayed_idxs(rows, self.MT.displayed_rows)
|
2358
|
-
event_data = self.MT.delete_rows_data(rows, event_data)
|
2359
|
-
event_data = self.MT.delete_rows_displayed(
|
2360
|
-
rows,
|
2361
|
-
event_data,
|
2362
|
-
)
|
2363
|
-
if undo:
|
2364
|
-
self.MT.undo_stack.append(stored_event_dict(event_data))
|
2365
|
-
if emit_event:
|
2366
|
-
self.emit_event("<<SheetModified>>", event_data)
|
2367
2333
|
self.set_refresh_timer(redraw)
|
2368
2334
|
return event_data
|
2369
2335
|
|
2336
|
+
del_row = del_rows
|
2337
|
+
delete_row = del_rows
|
2370
2338
|
delete_rows = del_rows
|
2371
2339
|
|
2372
2340
|
def del_columns(
|
2373
2341
|
self,
|
2374
2342
|
columns: int | AnyIter[int],
|
2375
2343
|
data_indexes: bool = True,
|
2376
|
-
undo: bool =
|
2344
|
+
undo: bool = True,
|
2377
2345
|
emit_event: bool = False,
|
2378
2346
|
redraw: bool = True,
|
2379
2347
|
) -> EventDataDict:
|
2380
|
-
self.MT.
|
2381
|
-
|
2382
|
-
|
2383
|
-
|
2384
|
-
|
2385
|
-
|
2386
|
-
boxes=self.MT.get_boxes(),
|
2387
|
-
selected=self.MT.selected,
|
2348
|
+
event_data = self.MT.delete_columns(
|
2349
|
+
columns=[columns] if isinstance(columns, int) else sorted(set(columns)),
|
2350
|
+
data_indexes=data_indexes,
|
2351
|
+
undo=undo,
|
2352
|
+
emit_event=emit_event,
|
2353
|
+
ext=True,
|
2388
2354
|
)
|
2389
|
-
if not data_indexes:
|
2390
|
-
event_data = self.MT.delete_columns_displayed(columns, event_data)
|
2391
|
-
event_data = self.MT.delete_columns_data(
|
2392
|
-
columns if self.MT.all_columns_displayed else [self.MT.displayed_columns[c] for c in columns],
|
2393
|
-
event_data,
|
2394
|
-
)
|
2395
|
-
else:
|
2396
|
-
if self.MT.all_columns_displayed:
|
2397
|
-
columns = columns
|
2398
|
-
else:
|
2399
|
-
columns = data_to_displayed_idxs(columns, self.MT.displayed_columns)
|
2400
|
-
event_data = self.MT.delete_columns_data(columns, event_data)
|
2401
|
-
event_data = self.MT.delete_columns_displayed(
|
2402
|
-
columns,
|
2403
|
-
event_data,
|
2404
|
-
)
|
2405
|
-
if undo:
|
2406
|
-
self.MT.undo_stack.append(stored_event_dict(event_data))
|
2407
|
-
if emit_event:
|
2408
|
-
self.emit_event("<<SheetModified>>", event_data)
|
2409
2355
|
self.set_refresh_timer(redraw)
|
2410
2356
|
return event_data
|
2411
2357
|
|
2358
|
+
del_column = del_columns
|
2359
|
+
delete_column = del_columns
|
2412
2360
|
delete_columns = del_columns
|
2413
2361
|
|
2414
2362
|
def sheet_data_dimensions(
|
@@ -2470,11 +2418,11 @@ class Sheet(tk.Frame):
|
|
2470
2418
|
self.MT.data_dimensions(total_columns=number)
|
2471
2419
|
return self
|
2472
2420
|
|
2473
|
-
def move_row(self, row: int, moveto: int) -> tuple[dict, dict,
|
2474
|
-
return self.move_rows(moveto, row)
|
2421
|
+
def move_row(self, row: int, moveto: int) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2422
|
+
return self.move_rows(moveto, [row])
|
2475
2423
|
|
2476
|
-
def move_column(self, column: int, moveto: int) -> tuple[dict, dict,
|
2477
|
-
return self.move_columns(moveto, column)
|
2424
|
+
def move_column(self, column: int, moveto: int) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2425
|
+
return self.move_columns(moveto, [column])
|
2478
2426
|
|
2479
2427
|
def move_rows(
|
2480
2428
|
self,
|
@@ -2483,11 +2431,16 @@ class Sheet(tk.Frame):
|
|
2483
2431
|
move_data: bool = True,
|
2484
2432
|
data_indexes: bool = False,
|
2485
2433
|
create_selections: bool = True,
|
2486
|
-
undo: bool =
|
2434
|
+
undo: bool = True,
|
2487
2435
|
emit_event: bool = False,
|
2488
2436
|
move_heights: bool = True,
|
2437
|
+
event_data: EventDataDict | None = None,
|
2489
2438
|
redraw: bool = True,
|
2490
|
-
) -> tuple[dict, dict,
|
2439
|
+
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2440
|
+
if not event_data:
|
2441
|
+
event_data = self.MT.new_event_dict("move_rows", state=True)
|
2442
|
+
if not data_indexes:
|
2443
|
+
event_data.value = move_to
|
2491
2444
|
data_idxs, disp_idxs, event_data = self.MT.move_rows_adjust_options_dict(
|
2492
2445
|
*self.MT.get_args_for_move_rows(
|
2493
2446
|
move_to=move_to,
|
@@ -2497,7 +2450,7 @@ class Sheet(tk.Frame):
|
|
2497
2450
|
move_data=move_data,
|
2498
2451
|
move_heights=move_heights,
|
2499
2452
|
create_selections=create_selections,
|
2500
|
-
|
2453
|
+
event_data=event_data,
|
2501
2454
|
)
|
2502
2455
|
if undo:
|
2503
2456
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2513,11 +2466,16 @@ class Sheet(tk.Frame):
|
|
2513
2466
|
move_data: bool = True,
|
2514
2467
|
data_indexes: bool = False,
|
2515
2468
|
create_selections: bool = True,
|
2516
|
-
undo: bool =
|
2469
|
+
undo: bool = True,
|
2517
2470
|
emit_event: bool = False,
|
2518
2471
|
move_widths: bool = True,
|
2472
|
+
event_data: EventDataDict | None = None,
|
2519
2473
|
redraw: bool = True,
|
2520
|
-
) -> tuple[dict, dict,
|
2474
|
+
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2475
|
+
if not event_data:
|
2476
|
+
event_data = self.MT.new_event_dict("move_columns", state=True)
|
2477
|
+
if not data_indexes:
|
2478
|
+
event_data.value = move_to
|
2521
2479
|
data_idxs, disp_idxs, event_data = self.MT.move_columns_adjust_options_dict(
|
2522
2480
|
*self.MT.get_args_for_move_columns(
|
2523
2481
|
move_to=move_to,
|
@@ -2527,7 +2485,7 @@ class Sheet(tk.Frame):
|
|
2527
2485
|
move_data=move_data,
|
2528
2486
|
move_widths=move_widths,
|
2529
2487
|
create_selections=create_selections,
|
2530
|
-
|
2488
|
+
event_data=event_data,
|
2531
2489
|
)
|
2532
2490
|
if undo:
|
2533
2491
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2541,9 +2499,8 @@ class Sheet(tk.Frame):
|
|
2541
2499
|
data_new_idxs: dict[int, int],
|
2542
2500
|
disp_new_idxs: None | dict[int, int] = None,
|
2543
2501
|
move_data: bool = True,
|
2544
|
-
data_indexes: bool = False,
|
2545
2502
|
create_selections: bool = True,
|
2546
|
-
undo: bool =
|
2503
|
+
undo: bool = True,
|
2547
2504
|
emit_event: bool = False,
|
2548
2505
|
redraw: bool = True,
|
2549
2506
|
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
@@ -2554,7 +2511,6 @@ class Sheet(tk.Frame):
|
|
2554
2511
|
disp_new_idxs=disp_new_idxs,
|
2555
2512
|
move_data=move_data,
|
2556
2513
|
create_selections=create_selections,
|
2557
|
-
data_indexes=data_indexes,
|
2558
2514
|
)
|
2559
2515
|
if undo:
|
2560
2516
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2568,10 +2524,10 @@ class Sheet(tk.Frame):
|
|
2568
2524
|
data_new_idxs: dict[int, int],
|
2569
2525
|
disp_new_idxs: None | dict[int, int] = None,
|
2570
2526
|
move_data: bool = True,
|
2571
|
-
data_indexes: bool = False,
|
2572
2527
|
create_selections: bool = True,
|
2573
|
-
undo: bool =
|
2528
|
+
undo: bool = True,
|
2574
2529
|
emit_event: bool = False,
|
2530
|
+
event_data: EventDataDict | None = None,
|
2575
2531
|
redraw: bool = True,
|
2576
2532
|
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2577
2533
|
data_idxs, disp_idxs, event_data = self.MT.move_rows_adjust_options_dict(
|
@@ -2581,7 +2537,7 @@ class Sheet(tk.Frame):
|
|
2581
2537
|
disp_new_idxs=disp_new_idxs,
|
2582
2538
|
move_data=move_data,
|
2583
2539
|
create_selections=create_selections,
|
2584
|
-
|
2540
|
+
event_data=event_data,
|
2585
2541
|
)
|
2586
2542
|
if undo:
|
2587
2543
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2622,6 +2578,102 @@ class Sheet(tk.Frame):
|
|
2622
2578
|
data_idxs,
|
2623
2579
|
)
|
2624
2580
|
|
2581
|
+
# Sorting
|
2582
|
+
|
2583
|
+
def sort(
|
2584
|
+
self,
|
2585
|
+
boxes: AnyIter[Sequence[int, int, int, int]] | Span | None = None,
|
2586
|
+
reverse: bool = False,
|
2587
|
+
row_wise: bool = False,
|
2588
|
+
validation: bool = True,
|
2589
|
+
key: Callable | None = None,
|
2590
|
+
undo: bool = True,
|
2591
|
+
) -> EventDataDict:
|
2592
|
+
"""
|
2593
|
+
Sort the data within specified box regions in the table.
|
2594
|
+
|
2595
|
+
This method sorts the data within one or multiple box regions defined by their coordinates. Each box's columns are sorted independently.
|
2596
|
+
|
2597
|
+
Args:
|
2598
|
+
boxes (AnyIter[Sequence[int, int, int, int]] | Span | None): An iterable of box coordinates. Each box is defined by:
|
2599
|
+
- From Row (inclusive)
|
2600
|
+
- From Column (inclusive)
|
2601
|
+
- Up To Row (exclusive)
|
2602
|
+
- Up To Column (exclusive)
|
2603
|
+
If None, it will sort the currently selected boxes or the entire table.
|
2604
|
+
If Span, it will use the span coordinates.
|
2605
|
+
|
2606
|
+
reverse (bool): If True, sorts in descending order. Default is False (ascending).
|
2607
|
+
|
2608
|
+
row_wise (bool): if True sorts cells row-wise. Default is column-wise
|
2609
|
+
|
2610
|
+
validation (bool): If True, checks if the new cell values are valid according to any restrictions
|
2611
|
+
(e.g., dropdown validations) before applying the sort. Default is True.
|
2612
|
+
|
2613
|
+
key (Callable | None): A function to extract a comparison key from each element in the columns.
|
2614
|
+
If None, a natural sorting key will be used, which can handle most Python objects, including:
|
2615
|
+
- None, booleans, numbers (int, float), datetime objects, strings, and unknown types.
|
2616
|
+
Note: Performance might be slow with the natural sort for very large datasets.
|
2617
|
+
|
2618
|
+
Returns:
|
2619
|
+
EventDataDict: A dictionary containing information about the sorting event, including changes made to the table.
|
2620
|
+
|
2621
|
+
Raises:
|
2622
|
+
ValueError: If the input boxes are not in the expected format or if the data cannot be sorted.
|
2623
|
+
|
2624
|
+
Note:
|
2625
|
+
- Sorting is performed column-wise within each box.
|
2626
|
+
- If validation is enabled, any cell content that fails validation will not be updated.
|
2627
|
+
- Any cell options attached to cells will not be moved. Event data can be used to re-locate them.
|
2628
|
+
"""
|
2629
|
+
if isinstance(boxes, Span):
|
2630
|
+
boxes = [boxes.coords]
|
2631
|
+
return self.MT.sort_boxes(
|
2632
|
+
boxes=boxes, reverse=reverse, row_wise=row_wise, validation=validation, key=key, undo=undo
|
2633
|
+
)
|
2634
|
+
|
2635
|
+
def sort_rows(
|
2636
|
+
self,
|
2637
|
+
rows: AnyIter[int] | Span | None = None,
|
2638
|
+
reverse: bool = False,
|
2639
|
+
validation: bool = True,
|
2640
|
+
key: Callable | None = None,
|
2641
|
+
undo: bool = True,
|
2642
|
+
) -> EventDataDict:
|
2643
|
+
if isinstance(rows, Span):
|
2644
|
+
rows = rows.rows
|
2645
|
+
return self.RI._sort_rows(rows=rows, reverse=reverse, validation=validation, key=key, undo=undo)
|
2646
|
+
|
2647
|
+
def sort_columns(
|
2648
|
+
self,
|
2649
|
+
columns: AnyIter[int] | Span | None = None,
|
2650
|
+
reverse: bool = False,
|
2651
|
+
validation: bool = True,
|
2652
|
+
key: Callable | None = None,
|
2653
|
+
undo: bool = True,
|
2654
|
+
) -> EventDataDict:
|
2655
|
+
if isinstance(columns, Span):
|
2656
|
+
columns = columns.columns
|
2657
|
+
return self.CH._sort_columns(columns=columns, reverse=reverse, validation=validation, key=key, undo=undo)
|
2658
|
+
|
2659
|
+
def sort_rows_by_column(
|
2660
|
+
self,
|
2661
|
+
column: int | None = None,
|
2662
|
+
reverse: bool = False,
|
2663
|
+
key: Callable | None = None,
|
2664
|
+
undo: bool = True,
|
2665
|
+
) -> EventDataDict:
|
2666
|
+
return self.CH._sort_rows_by_column(column=column, reverse=reverse, key=key, undo=undo)
|
2667
|
+
|
2668
|
+
def sort_columns_by_row(
|
2669
|
+
self,
|
2670
|
+
row: int | None = None,
|
2671
|
+
reverse: bool = False,
|
2672
|
+
key: Callable | None = None,
|
2673
|
+
undo: bool = True,
|
2674
|
+
) -> EventDataDict:
|
2675
|
+
return self.RI._sort_columns_by_row(row=row, reverse=reverse, key=key, undo=undo)
|
2676
|
+
|
2625
2677
|
# Highlighting Cells
|
2626
2678
|
|
2627
2679
|
def highlight(
|
@@ -3060,16 +3112,17 @@ class Sheet(tk.Frame):
|
|
3060
3112
|
|
3061
3113
|
# Text Font and Alignment
|
3062
3114
|
|
3063
|
-
def font(
|
3064
|
-
self
|
3065
|
-
|
3066
|
-
|
3067
|
-
) -> tuple[str, int, str]:
|
3068
|
-
return self.MT.set_table_font(newfont, reset_row_positions=reset_row_positions)
|
3115
|
+
def font(self, newfont: tuple[str, int, str] | None = None, **_) -> tuple[str, int, str]:
|
3116
|
+
return self.MT.set_table_font(newfont)
|
3117
|
+
|
3118
|
+
table_font = font
|
3069
3119
|
|
3070
3120
|
def header_font(self, newfont: tuple[str, int, str] | None = None) -> tuple[str, int, str]:
|
3071
3121
|
return self.MT.set_header_font(newfont)
|
3072
3122
|
|
3123
|
+
def index_font(self, newfont: tuple[str, int, str] | None = None) -> tuple[str, int, str]:
|
3124
|
+
return self.MT.set_index_font(newfont)
|
3125
|
+
|
3073
3126
|
def table_align(
|
3074
3127
|
self,
|
3075
3128
|
align: str | None = None,
|
@@ -3080,7 +3133,7 @@ class Sheet(tk.Frame):
|
|
3080
3133
|
elif convert_align(align):
|
3081
3134
|
self.MT.align = convert_align(align)
|
3082
3135
|
else:
|
3083
|
-
raise ValueError(
|
3136
|
+
raise ValueError()
|
3084
3137
|
return self.set_refresh_timer(redraw)
|
3085
3138
|
|
3086
3139
|
def header_align(
|
@@ -3093,7 +3146,7 @@ class Sheet(tk.Frame):
|
|
3093
3146
|
elif convert_align(align):
|
3094
3147
|
self.CH.align = convert_align(align)
|
3095
3148
|
else:
|
3096
|
-
raise ValueError(
|
3149
|
+
raise ValueError(align_value_error)
|
3097
3150
|
return self.set_refresh_timer(redraw)
|
3098
3151
|
|
3099
3152
|
def row_index_align(
|
@@ -3106,7 +3159,7 @@ class Sheet(tk.Frame):
|
|
3106
3159
|
elif convert_align(align):
|
3107
3160
|
self.RI.align = convert_align(align)
|
3108
3161
|
else:
|
3109
|
-
raise ValueError(
|
3162
|
+
raise ValueError(align_value_error)
|
3110
3163
|
return self.set_refresh_timer(redraw)
|
3111
3164
|
|
3112
3165
|
index_align = row_index_align
|
@@ -3569,18 +3622,41 @@ class Sheet(tk.Frame):
|
|
3569
3622
|
only_set_if_too_small: bool = False,
|
3570
3623
|
redraw: bool = True,
|
3571
3624
|
) -> Sheet | int:
|
3572
|
-
if column == "all"
|
3573
|
-
|
3574
|
-
|
3575
|
-
|
3576
|
-
self.
|
3577
|
-
|
3578
|
-
|
3579
|
-
|
3580
|
-
|
3625
|
+
if column == "all":
|
3626
|
+
if width == "default":
|
3627
|
+
self.MT.reset_col_positions()
|
3628
|
+
elif width == "text":
|
3629
|
+
self.set_all_column_widths(only_set_if_too_small=only_set_if_too_small)
|
3630
|
+
elif isinstance(width, int):
|
3631
|
+
self.MT.reset_col_positions(width=width)
|
3632
|
+
|
3633
|
+
elif column == "displayed":
|
3634
|
+
if width == "default":
|
3635
|
+
for c in range(*self.MT.visible_text_columns):
|
3636
|
+
self.CH.set_col_width(
|
3637
|
+
c, width=self.ops.default_column_width, only_if_too_small=only_set_if_too_small
|
3638
|
+
)
|
3639
|
+
elif width == "text":
|
3640
|
+
for c in range(*self.MT.visible_text_columns):
|
3641
|
+
self.CH.set_col_width(c, only_if_too_small=only_set_if_too_small)
|
3642
|
+
elif isinstance(width, int):
|
3643
|
+
for c in range(*self.MT.visible_text_columns):
|
3644
|
+
self.CH.set_col_width(c, width=width, only_if_too_small=only_set_if_too_small)
|
3645
|
+
|
3581
3646
|
elif isinstance(column, int):
|
3582
|
-
|
3583
|
-
|
3647
|
+
if width == "default":
|
3648
|
+
self.CH.set_col_width(
|
3649
|
+
col=column, width=self.ops.default_column_width, only_if_too_small=only_set_if_too_small
|
3650
|
+
)
|
3651
|
+
elif width == "text":
|
3652
|
+
self.CH.set_col_width(col=column, only_if_too_small=only_set_if_too_small)
|
3653
|
+
elif isinstance(width, int):
|
3654
|
+
self.CH.set_col_width(col=column, width=width, only_if_too_small=only_set_if_too_small)
|
3655
|
+
elif width is None:
|
3656
|
+
return int(self.MT.col_positions[column + 1] - self.MT.col_positions[column])
|
3657
|
+
|
3658
|
+
else:
|
3659
|
+
return self.set_refresh_timer(redraw)
|
3584
3660
|
|
3585
3661
|
def row_height(
|
3586
3662
|
self,
|
@@ -3589,18 +3665,39 @@ class Sheet(tk.Frame):
|
|
3589
3665
|
only_set_if_too_small: bool = False,
|
3590
3666
|
redraw: bool = True,
|
3591
3667
|
) -> Sheet | int:
|
3592
|
-
if row == "all"
|
3593
|
-
|
3594
|
-
|
3595
|
-
|
3596
|
-
self.
|
3597
|
-
|
3598
|
-
|
3599
|
-
|
3600
|
-
|
3668
|
+
if row == "all":
|
3669
|
+
if height == "default":
|
3670
|
+
self.MT.reset_row_positions()
|
3671
|
+
elif height == "text":
|
3672
|
+
self.set_all_row_heights()
|
3673
|
+
elif isinstance(height, int):
|
3674
|
+
self.MT.reset_row_positions(height=height)
|
3675
|
+
|
3676
|
+
elif row == "displayed":
|
3677
|
+
if height == "default":
|
3678
|
+
height = self.MT.get_default_row_height()
|
3679
|
+
for r in range(*self.MT.visible_text_rows):
|
3680
|
+
self.RI.set_row_height(r, height=height, only_if_too_small=only_set_if_too_small)
|
3681
|
+
elif height == "text":
|
3682
|
+
for r in range(*self.MT.visible_text_rows):
|
3683
|
+
self.RI.set_row_height(r, only_if_too_small=only_set_if_too_small)
|
3684
|
+
elif isinstance(height, int):
|
3685
|
+
for r in range(*self.MT.visible_text_rows):
|
3686
|
+
self.RI.set_row_height(r, height=height, only_if_too_small=only_set_if_too_small)
|
3687
|
+
|
3601
3688
|
elif isinstance(row, int):
|
3602
|
-
|
3603
|
-
|
3689
|
+
if height == "default":
|
3690
|
+
height = self.MT.get_default_row_height()
|
3691
|
+
self.RI.set_row_height(row=row, height=height, only_if_too_small=only_set_if_too_small)
|
3692
|
+
elif height == "text":
|
3693
|
+
self.RI.set_row_height(row=row, only_if_too_small=only_set_if_too_small)
|
3694
|
+
elif isinstance(height, int):
|
3695
|
+
self.RI.set_row_height(row=row, height=height, only_if_too_small=only_set_if_too_small)
|
3696
|
+
elif height is None:
|
3697
|
+
return int(self.MT.row_positions[row + 1] - self.MT.row_positions[row])
|
3698
|
+
|
3699
|
+
else:
|
3700
|
+
return self.set_refresh_timer(redraw)
|
3604
3701
|
|
3605
3702
|
def get_column_widths(self, canvas_positions: bool = False) -> list[float]:
|
3606
3703
|
if canvas_positions:
|
@@ -3734,7 +3831,7 @@ class Sheet(tk.Frame):
|
|
3734
3831
|
deselect_all: bool = False,
|
3735
3832
|
redraw: bool = False,
|
3736
3833
|
) -> Sheet:
|
3737
|
-
self.MT.
|
3834
|
+
self.MT.insert_col_positions(idx=idx, widths=width, deselect_all=deselect_all)
|
3738
3835
|
return self.set_refresh_timer(redraw)
|
3739
3836
|
|
3740
3837
|
def insert_row_position(
|
@@ -3744,7 +3841,7 @@ class Sheet(tk.Frame):
|
|
3744
3841
|
deselect_all: bool = False,
|
3745
3842
|
redraw: bool = False,
|
3746
3843
|
) -> Sheet:
|
3747
|
-
self.MT.
|
3844
|
+
self.MT.insert_row_positions(idx=idx, heights=height, deselect_all=deselect_all)
|
3748
3845
|
return self.set_refresh_timer(redraw)
|
3749
3846
|
|
3750
3847
|
def insert_column_positions(
|
@@ -4076,11 +4173,12 @@ class Sheet(tk.Frame):
|
|
4076
4173
|
if isinstance(columns, int):
|
4077
4174
|
columns = [columns]
|
4078
4175
|
cws = self.MT.get_column_widths()
|
4176
|
+
default_col_w = self.ops.default_column_width
|
4079
4177
|
for column in columns:
|
4080
4178
|
idx = bisect_left(self.MT.displayed_columns, column)
|
4081
4179
|
if len(self.MT.displayed_columns) == idx or self.MT.displayed_columns[idx] != column:
|
4082
4180
|
self.MT.displayed_columns.insert(idx, column)
|
4083
|
-
cws.insert(idx, self.MT.saved_column_widths.pop(column,
|
4181
|
+
cws.insert(idx, self.MT.saved_column_widths.pop(column, default_col_w))
|
4084
4182
|
self.MT.set_col_positions(cws)
|
4085
4183
|
if deselect_all:
|
4086
4184
|
self.MT.deselect(redraw=False)
|
@@ -4209,12 +4307,13 @@ class Sheet(tk.Frame):
|
|
4209
4307
|
return
|
4210
4308
|
if isinstance(rows, int):
|
4211
4309
|
rows = [rows]
|
4310
|
+
default_row_h = self.MT.get_default_row_height()
|
4212
4311
|
rhs = self.MT.get_row_heights()
|
4213
4312
|
for row in rows:
|
4214
4313
|
idx = bisect_left(self.MT.displayed_rows, row)
|
4215
4314
|
if len(self.MT.displayed_rows) == idx or self.MT.displayed_rows[idx] != row:
|
4216
4315
|
self.MT.displayed_rows.insert(idx, row)
|
4217
|
-
rhs.insert(idx, self.MT.saved_row_heights.pop(row,
|
4316
|
+
rhs.insert(idx, self.MT.saved_row_heights.pop(row, default_row_h))
|
4218
4317
|
self.MT.set_row_positions(rhs)
|
4219
4318
|
if deselect_all:
|
4220
4319
|
self.MT.deselect(redraw=False)
|
@@ -4249,52 +4348,6 @@ class Sheet(tk.Frame):
|
|
4249
4348
|
|
4250
4349
|
# Hiding Sheet Elements
|
4251
4350
|
|
4252
|
-
def hide(
|
4253
|
-
self,
|
4254
|
-
canvas: Literal[
|
4255
|
-
"all",
|
4256
|
-
"row_index",
|
4257
|
-
"header",
|
4258
|
-
"top_left",
|
4259
|
-
"x_scrollbar",
|
4260
|
-
"y_scrollbar",
|
4261
|
-
] = "all",
|
4262
|
-
) -> Sheet:
|
4263
|
-
if canvas.lower() == "all":
|
4264
|
-
self.TL.grid_forget()
|
4265
|
-
self.RI.grid_forget()
|
4266
|
-
self.RI["yscrollcommand"] = 0
|
4267
|
-
self.MT.show_index = False
|
4268
|
-
self.CH.grid_forget()
|
4269
|
-
self.CH["xscrollcommand"] = 0
|
4270
|
-
self.MT.show_header = False
|
4271
|
-
self.MT.grid_forget()
|
4272
|
-
self.yscroll.grid_forget()
|
4273
|
-
self.xscroll.grid_forget()
|
4274
|
-
self.xscroll_showing = False
|
4275
|
-
self.yscroll_showing = False
|
4276
|
-
self.xscroll_disabled = True
|
4277
|
-
self.yscroll_disabled = True
|
4278
|
-
elif canvas.lower() == "row_index":
|
4279
|
-
self.RI.grid_forget()
|
4280
|
-
self.RI["yscrollcommand"] = 0
|
4281
|
-
self.MT.show_index = False
|
4282
|
-
elif canvas.lower() == "header":
|
4283
|
-
self.CH.grid_forget()
|
4284
|
-
self.CH["xscrollcommand"] = 0
|
4285
|
-
self.MT.show_header = False
|
4286
|
-
elif canvas.lower() == "top_left":
|
4287
|
-
self.TL.grid_forget()
|
4288
|
-
elif canvas.lower() == "x_scrollbar":
|
4289
|
-
self.xscroll.grid_forget()
|
4290
|
-
self.xscroll_showing = False
|
4291
|
-
self.xscroll_disabled = True
|
4292
|
-
elif canvas.lower() == "y_scrollbar":
|
4293
|
-
self.yscroll.grid_forget()
|
4294
|
-
self.yscroll_showing = False
|
4295
|
-
self.yscroll_disabled = True
|
4296
|
-
return self
|
4297
|
-
|
4298
4351
|
def show(
|
4299
4352
|
self,
|
4300
4353
|
canvas: Literal[
|
@@ -4305,45 +4358,75 @@ class Sheet(tk.Frame):
|
|
4305
4358
|
"top_left",
|
4306
4359
|
"x_scrollbar",
|
4307
4360
|
"y_scrollbar",
|
4361
|
+
"table",
|
4308
4362
|
] = "all",
|
4309
4363
|
) -> Sheet:
|
4310
|
-
if canvas
|
4311
|
-
self.hide()
|
4312
|
-
self.TL.grid(row=0, column=0)
|
4313
|
-
self.RI.grid(row=1, column=0, sticky="nswe")
|
4314
|
-
self.CH.grid(row=0, column=1, sticky="nswe")
|
4364
|
+
if canvas in ("all", "table"):
|
4315
4365
|
self.MT.grid(row=1, column=1, sticky="nswe")
|
4316
|
-
|
4317
|
-
self.xscroll.grid(row=2, column=0, columnspan=2, sticky="nswe")
|
4318
|
-
self.MT["xscrollcommand"] = self.xscroll.set
|
4319
|
-
self.CH["xscrollcommand"] = self.xscroll.set
|
4320
|
-
self.MT["yscrollcommand"] = self.yscroll.set
|
4321
|
-
self.RI["yscrollcommand"] = self.yscroll.set
|
4322
|
-
self.xscroll_showing = True
|
4323
|
-
self.yscroll_showing = True
|
4324
|
-
self.xscroll_disabled = False
|
4325
|
-
self.yscroll_disabled = False
|
4326
|
-
elif canvas in ("row_index", "index"):
|
4366
|
+
if canvas in ("all", "row_index", "index"):
|
4327
4367
|
self.RI.grid(row=1, column=0, sticky="nswe")
|
4328
4368
|
self.MT["yscrollcommand"] = self.yscroll.set
|
4329
4369
|
self.RI["yscrollcommand"] = self.yscroll.set
|
4330
4370
|
self.MT.show_index = True
|
4331
|
-
|
4371
|
+
if self.MT.show_header:
|
4372
|
+
self.show("top_left")
|
4373
|
+
if canvas in ("all", "header"):
|
4332
4374
|
self.CH.grid(row=0, column=1, sticky="nswe")
|
4333
4375
|
self.MT["xscrollcommand"] = self.xscroll.set
|
4334
4376
|
self.CH["xscrollcommand"] = self.xscroll.set
|
4335
4377
|
self.MT.show_header = True
|
4336
|
-
|
4378
|
+
if self.MT.show_index:
|
4379
|
+
self.show("top_left")
|
4380
|
+
if canvas in ("all", "top_left"):
|
4337
4381
|
self.TL.grid(row=0, column=0)
|
4338
|
-
|
4382
|
+
if canvas in ("all", "x_scrollbar"):
|
4339
4383
|
self.xscroll.grid(row=2, column=0, columnspan=2, sticky="nswe")
|
4340
4384
|
self.xscroll_showing = True
|
4341
4385
|
self.xscroll_disabled = False
|
4342
|
-
|
4386
|
+
if canvas in ("all", "y_scrollbar"):
|
4343
4387
|
self.yscroll.grid(row=0, column=2, rowspan=3, sticky="nswe")
|
4344
4388
|
self.yscroll_showing = True
|
4345
4389
|
self.yscroll_disabled = False
|
4346
|
-
self.
|
4390
|
+
if self._startup_complete:
|
4391
|
+
self.MT.update_idletasks()
|
4392
|
+
return self
|
4393
|
+
|
4394
|
+
def hide(
|
4395
|
+
self,
|
4396
|
+
canvas: Literal[
|
4397
|
+
"all",
|
4398
|
+
"row_index",
|
4399
|
+
"header",
|
4400
|
+
"top_left",
|
4401
|
+
"x_scrollbar",
|
4402
|
+
"y_scrollbar",
|
4403
|
+
"table",
|
4404
|
+
] = "all",
|
4405
|
+
) -> Sheet:
|
4406
|
+
if canvas in ("all", "row_index"):
|
4407
|
+
self.RI.grid_remove()
|
4408
|
+
self.RI["yscrollcommand"] = 0
|
4409
|
+
self.MT.show_index = False
|
4410
|
+
if not self.ops.show_top_left:
|
4411
|
+
self.hide("top_left")
|
4412
|
+
if canvas in ("all", "header"):
|
4413
|
+
self.CH.grid_remove()
|
4414
|
+
self.CH["xscrollcommand"] = 0
|
4415
|
+
self.MT.show_header = False
|
4416
|
+
if not self.ops.show_top_left:
|
4417
|
+
self.hide("top_left")
|
4418
|
+
if canvas in ("all", "top_left"):
|
4419
|
+
self.TL.grid_remove()
|
4420
|
+
if canvas in ("all", "x_scrollbar"):
|
4421
|
+
self.xscroll.grid_remove()
|
4422
|
+
self.xscroll_showing = False
|
4423
|
+
self.xscroll_disabled = True
|
4424
|
+
if canvas in ("all", "y_scrollbar"):
|
4425
|
+
self.yscroll.grid_remove()
|
4426
|
+
self.yscroll_showing = False
|
4427
|
+
self.yscroll_disabled = True
|
4428
|
+
if canvas in ("all", "table"):
|
4429
|
+
self.MT.grid_remove()
|
4347
4430
|
return self
|
4348
4431
|
|
4349
4432
|
# Sheet Height and Width
|
@@ -4479,6 +4562,8 @@ class Sheet(tk.Frame):
|
|
4479
4562
|
if "expand_sheet_if_paste_too_big" in kwargs:
|
4480
4563
|
self.ops.paste_can_expand_x = kwargs["expand_sheet_if_paste_too_big"]
|
4481
4564
|
self.ops.paste_can_expand_y = kwargs["expand_sheet_if_paste_too_big"]
|
4565
|
+
if "show_top_left" in kwargs:
|
4566
|
+
self.show("top_left")
|
4482
4567
|
if "font" in kwargs:
|
4483
4568
|
self.MT.set_table_font(kwargs["font"])
|
4484
4569
|
elif "table_font" in kwargs:
|
@@ -4514,7 +4599,7 @@ class Sheet(tk.Frame):
|
|
4514
4599
|
self.set_scrollbar_options()
|
4515
4600
|
self.MT.create_rc_menus()
|
4516
4601
|
if "treeview" in kwargs:
|
4517
|
-
self.index_align("
|
4602
|
+
self.index_align("nw", redraw=False)
|
4518
4603
|
return self.set_refresh_timer(redraw)
|
4519
4604
|
|
4520
4605
|
def set_scrollbar_options(self) -> Sheet:
|
@@ -4571,15 +4656,7 @@ class Sheet(tk.Frame):
|
|
4571
4656
|
self,
|
4572
4657
|
row: int,
|
4573
4658
|
column: int | str,
|
4574
|
-
key: None
|
4575
|
-
| Literal[
|
4576
|
-
"format",
|
4577
|
-
"highlight",
|
4578
|
-
"dropdown",
|
4579
|
-
"checkbox",
|
4580
|
-
"readonly",
|
4581
|
-
"align",
|
4582
|
-
] = None,
|
4659
|
+
key: None | CellPropertyKey = None,
|
4583
4660
|
cellops: bool = True,
|
4584
4661
|
rowops: bool = True,
|
4585
4662
|
columnops: bool = True,
|
@@ -4613,15 +4690,7 @@ class Sheet(tk.Frame):
|
|
4613
4690
|
def index_props(
|
4614
4691
|
self,
|
4615
4692
|
row: int,
|
4616
|
-
key: None
|
4617
|
-
| Literal[
|
4618
|
-
"format",
|
4619
|
-
"highlight",
|
4620
|
-
"dropdown",
|
4621
|
-
"checkbox",
|
4622
|
-
"readonly",
|
4623
|
-
"align",
|
4624
|
-
] = None,
|
4693
|
+
key: None | CellPropertyKey = None,
|
4625
4694
|
) -> dict:
|
4626
4695
|
"""
|
4627
4696
|
Retrieve options (properties - props)
|
@@ -4637,15 +4706,7 @@ class Sheet(tk.Frame):
|
|
4637
4706
|
def header_props(
|
4638
4707
|
self,
|
4639
4708
|
column: int | str,
|
4640
|
-
key: None
|
4641
|
-
| Literal[
|
4642
|
-
"format",
|
4643
|
-
"highlight",
|
4644
|
-
"dropdown",
|
4645
|
-
"checkbox",
|
4646
|
-
"readonly",
|
4647
|
-
"align",
|
4648
|
-
] = None,
|
4709
|
+
key: None | CellPropertyKey = None,
|
4649
4710
|
) -> dict:
|
4650
4711
|
"""
|
4651
4712
|
Retrieve options (properties - props)
|
@@ -4662,7 +4723,7 @@ class Sheet(tk.Frame):
|
|
4662
4723
|
|
4663
4724
|
def get_cell_options(
|
4664
4725
|
self,
|
4665
|
-
key: None |
|
4726
|
+
key: None | CellPropertyKey = None,
|
4666
4727
|
canvas: Literal["table", "row_index", "index", "header"] = "table",
|
4667
4728
|
) -> dict:
|
4668
4729
|
if canvas == "table":
|
@@ -4675,22 +4736,22 @@ class Sheet(tk.Frame):
|
|
4675
4736
|
return target
|
4676
4737
|
return {k: v[key] for k, v in target.items() if key in v}
|
4677
4738
|
|
4678
|
-
def get_row_options(self, key: None |
|
4739
|
+
def get_row_options(self, key: None | CellPropertyKey = None) -> dict:
|
4679
4740
|
if key is None:
|
4680
4741
|
return self.MT.row_options
|
4681
4742
|
return {k: v[key] for k, v in self.MT.row_options.items() if key in v}
|
4682
4743
|
|
4683
|
-
def get_column_options(self, key: None |
|
4744
|
+
def get_column_options(self, key: None | CellPropertyKey = None) -> dict:
|
4684
4745
|
if key is None:
|
4685
4746
|
return self.MT.col_options
|
4686
4747
|
return {k: v[key] for k, v in self.MT.col_options.items() if key in v}
|
4687
4748
|
|
4688
|
-
def get_index_options(self, key: None |
|
4749
|
+
def get_index_options(self, key: None | CellPropertyKey = None) -> dict:
|
4689
4750
|
if key is None:
|
4690
4751
|
return self.RI.cell_options
|
4691
4752
|
return {k: v[key] for k, v in self.RI.cell_options.items() if key in v}
|
4692
4753
|
|
4693
|
-
def get_header_options(self, key: None |
|
4754
|
+
def get_header_options(self, key: None | CellPropertyKey = None) -> dict:
|
4694
4755
|
if key is None:
|
4695
4756
|
return self.CH.cell_options
|
4696
4757
|
return {k: v[key] for k, v in self.CH.cell_options.items() if key in v}
|
@@ -4958,94 +5019,21 @@ class Sheet(tk.Frame):
|
|
4958
5019
|
include_parent_column: bool = True,
|
4959
5020
|
include_text_column: bool = True,
|
4960
5021
|
) -> Sheet:
|
4961
|
-
self.
|
4962
|
-
|
4963
|
-
|
4964
|
-
|
4965
|
-
|
4966
|
-
ncols = max(map(len, data), default=0)
|
4967
|
-
for rn, row in enumerate(data):
|
4968
|
-
if safety and ncols > (lnr := len(row)):
|
4969
|
-
row += self.MT.get_empty_row_seq(rn, end=ncols, start=lnr)
|
4970
|
-
if lower:
|
4971
|
-
iid = row[iid_column].lower()
|
4972
|
-
pid = row[parent_column].lower()
|
4973
|
-
else:
|
4974
|
-
iid = row[iid_column]
|
4975
|
-
pid = row[parent_column]
|
4976
|
-
if safety:
|
4977
|
-
if not iid:
|
4978
|
-
continue
|
4979
|
-
tally_of_ids[iid] += 1
|
4980
|
-
if tally_of_ids[iid]:
|
4981
|
-
x = 1
|
4982
|
-
while iid in tally_of_ids:
|
4983
|
-
new = f"{row[iid_column]}_DUPLICATED_{x}"
|
4984
|
-
iid = new.lower() if lower else new
|
4985
|
-
x += 1
|
4986
|
-
tally_of_ids[iid] += 1
|
4987
|
-
row[iid_column] = new
|
4988
|
-
if iid in self.RI.tree:
|
4989
|
-
self.RI.tree[iid].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
4990
|
-
else:
|
4991
|
-
self.RI.tree[iid] = Node(row[text_column] if isinstance(text_column, int) else text_column[rn], iid, "")
|
4992
|
-
if safety and (iid == pid or self.RI.build_pid_causes_recursive_loop(iid, pid)):
|
4993
|
-
row[parent_column] = ""
|
4994
|
-
pid = ""
|
4995
|
-
if pid:
|
4996
|
-
if pid not in self.RI.tree:
|
4997
|
-
self.RI.tree[pid] = Node(row[text_column] if isinstance(text_column, int) else text_column[rn], pid)
|
4998
|
-
self.RI.tree[iid].parent = self.RI.tree[pid]
|
4999
|
-
self.RI.tree[pid].children.append(self.RI.tree[iid])
|
5000
|
-
else:
|
5001
|
-
self.RI.tree[iid].parent = ""
|
5002
|
-
self.RI.tree_rns[iid] = rn
|
5003
|
-
if safety:
|
5004
|
-
for n in self.RI.tree.values():
|
5005
|
-
if n.parent is None:
|
5006
|
-
n.parent = ""
|
5007
|
-
newrow = self.MT.get_empty_row_seq(len(data), ncols)
|
5008
|
-
newrow[iid_column] = n.iid
|
5009
|
-
self.RI.tree_rns[n.iid] = len(data)
|
5010
|
-
data.append(newrow)
|
5011
|
-
insert_rows = partial(
|
5012
|
-
self.insert_rows,
|
5013
|
-
idx=0,
|
5014
|
-
heights={} if row_heights is False else row_heights,
|
5015
|
-
row_index=True,
|
5016
|
-
create_selections=False,
|
5017
|
-
fill=False,
|
5022
|
+
self.RI.tree_build(
|
5023
|
+
data=data,
|
5024
|
+
iid_column=iid_column,
|
5025
|
+
parent_column=parent_column,
|
5026
|
+
text_column=text_column,
|
5018
5027
|
push_ops=push_ops,
|
5019
|
-
|
5028
|
+
row_heights=row_heights,
|
5029
|
+
open_ids=open_ids,
|
5030
|
+
safety=safety,
|
5031
|
+
ncols=ncols,
|
5032
|
+
lower=lower,
|
5033
|
+
include_iid_column=include_iid_column,
|
5034
|
+
include_parent_column=include_parent_column,
|
5035
|
+
include_text_column=include_text_column,
|
5020
5036
|
)
|
5021
|
-
exclude = set()
|
5022
|
-
if not include_iid_column:
|
5023
|
-
exclude.add(iid_column)
|
5024
|
-
if not include_parent_column:
|
5025
|
-
exclude.add(parent_column)
|
5026
|
-
if isinstance(text_column, int) and not include_text_column:
|
5027
|
-
exclude.add(text_column)
|
5028
|
-
if exclude:
|
5029
|
-
insert_rows(
|
5030
|
-
rows=[
|
5031
|
-
[self.RI.tree[iid]] + [e for i, e in enumerate(data[self.RI.tree_rns[iid]]) if i not in exclude]
|
5032
|
-
for iid in self.get_nodes()
|
5033
|
-
]
|
5034
|
-
)
|
5035
|
-
else:
|
5036
|
-
insert_rows(rows=[[self.RI.tree[iid]] + data[self.RI.tree_rns[iid]] for iid in self.get_nodes()])
|
5037
|
-
self.MT.all_rows_displayed = False
|
5038
|
-
self.MT.displayed_rows = list(range(len(self.MT._row_index)))
|
5039
|
-
self.RI.tree_rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
5040
|
-
if open_ids:
|
5041
|
-
self.tree_set_open(open_ids=open_ids)
|
5042
|
-
else:
|
5043
|
-
self.hide_rows(
|
5044
|
-
{self.RI.tree_rns[iid] for iid in self.get_children() if self.RI.tree[iid].parent},
|
5045
|
-
deselect_all=False,
|
5046
|
-
data_indexes=True,
|
5047
|
-
row_heights=False if row_heights is False else True,
|
5048
|
-
)
|
5049
5037
|
return self
|
5050
5038
|
|
5051
5039
|
def tree_reset(self) -> Sheet:
|
@@ -5153,6 +5141,7 @@ class Sheet(tk.Frame):
|
|
5153
5141
|
text: None | str = None,
|
5154
5142
|
values: None | list[object] = None,
|
5155
5143
|
create_selections: bool = False,
|
5144
|
+
undo: bool = True,
|
5156
5145
|
) -> str:
|
5157
5146
|
"""
|
5158
5147
|
Insert an item into the treeview
|
@@ -5161,9 +5150,7 @@ class Sheet(tk.Frame):
|
|
5161
5150
|
str: new item iid
|
5162
5151
|
"""
|
5163
5152
|
if not iid:
|
5164
|
-
|
5165
|
-
while (iid := f"{num2alpha(i)}") in self.RI.tree:
|
5166
|
-
i += 1
|
5153
|
+
iid = self.RI.new_iid()
|
5167
5154
|
if iid in self.RI.tree:
|
5168
5155
|
raise ValueError(f"iid '{iid}' already exists.")
|
5169
5156
|
if iid == parent:
|
@@ -5172,18 +5159,37 @@ class Sheet(tk.Frame):
|
|
5172
5159
|
raise ValueError(f"parent '{parent}' does not exist.")
|
5173
5160
|
if text is None:
|
5174
5161
|
text = iid
|
5175
|
-
|
5176
|
-
|
5177
|
-
|
5162
|
+
new_node = Node(text, iid, parent)
|
5163
|
+
datarn = self._get_id_insert_row(index=index, parent=parent)
|
5164
|
+
self.insert_rows(
|
5165
|
+
rows=[[new_node] + ([] if values is None else values)],
|
5166
|
+
idx=datarn,
|
5167
|
+
row_index=True,
|
5168
|
+
create_selections=create_selections,
|
5169
|
+
fill=False,
|
5170
|
+
undo=undo,
|
5171
|
+
tree=True,
|
5172
|
+
)
|
5173
|
+
# only relevant here because in rc add rows they are visible and undo sets old open_ids
|
5174
|
+
if parent and (parent not in self.RI.tree_open_ids or not self.item_displayed(parent)):
|
5175
|
+
self.hide_rows(datarn, deselect_all=False, data_indexes=True)
|
5176
|
+
return iid
|
5177
|
+
|
5178
|
+
def _get_id_insert_row(self, index: int, parent: str) -> int:
|
5179
|
+
if parent:
|
5178
5180
|
if isinstance(index, int):
|
5179
|
-
|
5180
|
-
datarn
|
5181
|
-
|
5181
|
+
index = min(index, len(self.RI.tree[parent].children))
|
5182
|
+
datarn = (
|
5183
|
+
self.RI.tree_rns[parent]
|
5184
|
+
+ index
|
5185
|
+
+ 1
|
5186
|
+
+ sum(
|
5187
|
+
sum(1 for _ in self.RI.get_iid_descendants(cid))
|
5188
|
+
for cid in islice(self.get_children(parent), index)
|
5189
|
+
)
|
5182
5190
|
)
|
5183
|
-
self.RI.tree[parent].children.insert(index, self.RI.tree[iid])
|
5184
5191
|
else:
|
5185
5192
|
datarn = self.RI.tree_rns[parent] + sum(1 for _ in self.RI.get_iid_descendants(parent)) + 1
|
5186
|
-
self.RI.tree[parent].children.append(self.RI.tree[iid])
|
5187
5193
|
else:
|
5188
5194
|
if isinstance(index, int):
|
5189
5195
|
datarn = index
|
@@ -5191,19 +5197,7 @@ class Sheet(tk.Frame):
|
|
5191
5197
|
datarn = len(self.MT._row_index)
|
5192
5198
|
else:
|
5193
5199
|
datarn = len(self.MT._row_index)
|
5194
|
-
|
5195
|
-
values = []
|
5196
|
-
self.insert_rows(
|
5197
|
-
rows=[[self.RI.tree[iid]] + values],
|
5198
|
-
idx=datarn,
|
5199
|
-
row_index=True,
|
5200
|
-
create_selections=create_selections,
|
5201
|
-
fill=False,
|
5202
|
-
)
|
5203
|
-
self.RI.tree_rns[iid] = datarn
|
5204
|
-
if parent and (parent not in self.RI.tree_open_ids or not self.item_displayed(parent)):
|
5205
|
-
self.hide_rows(datarn, deselect_all=False, data_indexes=True)
|
5206
|
-
return iid
|
5200
|
+
return datarn
|
5207
5201
|
|
5208
5202
|
def bulk_insert(
|
5209
5203
|
self,
|
@@ -5215,6 +5209,7 @@ class Sheet(tk.Frame):
|
|
5215
5209
|
create_selections: bool = False,
|
5216
5210
|
include_iid_column: bool = True,
|
5217
5211
|
include_text_column: bool = True,
|
5212
|
+
undo: bool = True,
|
5218
5213
|
) -> dict[str, int]:
|
5219
5214
|
"""
|
5220
5215
|
Insert multiple items into the treeview at once, under the same parent.
|
@@ -5225,52 +5220,29 @@ class Sheet(tk.Frame):
|
|
5225
5220
|
- Values (int): row numbers
|
5226
5221
|
"""
|
5227
5222
|
to_insert = []
|
5228
|
-
|
5229
|
-
if pid and pid not in self.RI.tree:
|
5223
|
+
if parent and parent not in self.RI.tree:
|
5230
5224
|
raise ValueError(f"parent '{parent}' does not exist.")
|
5231
|
-
|
5232
|
-
if parent_node:
|
5233
|
-
if isinstance(index, int):
|
5234
|
-
datarn = self.RI.tree_rns[pid] + index + 1
|
5235
|
-
datarn += sum(
|
5236
|
-
sum(1 for _ in self.RI.get_iid_descendants(cid)) for cid in islice(self.get_children(pid), index)
|
5237
|
-
)
|
5238
|
-
else:
|
5239
|
-
datarn = self.RI.tree_rns[pid] + sum(1 for _ in self.RI.get_iid_descendants(pid)) + 1
|
5240
|
-
else:
|
5241
|
-
if isinstance(index, int):
|
5242
|
-
datarn = index
|
5243
|
-
if index and (datarn := self.top_index_row(datarn)) is None:
|
5244
|
-
datarn = len(self.MT._row_index)
|
5245
|
-
else:
|
5246
|
-
datarn = len(self.MT._row_index)
|
5247
|
-
i = 0
|
5225
|
+
datarn = self._get_id_insert_row(index=index, parent=parent)
|
5248
5226
|
rns_to_add = {}
|
5249
5227
|
for rn, r in enumerate(data, start=datarn):
|
5250
5228
|
if iid_column is None:
|
5251
|
-
|
5252
|
-
i += 1
|
5229
|
+
iid = self.RI.new_iid()
|
5253
5230
|
else:
|
5254
5231
|
iid = r[iid_column]
|
5255
|
-
|
5232
|
+
new_node = Node(
|
5256
5233
|
r[text_column] if isinstance(text_column, int) else text_column if isinstance(text_column, str) else "",
|
5257
5234
|
iid,
|
5258
|
-
|
5235
|
+
parent,
|
5259
5236
|
)
|
5260
|
-
if parent_node:
|
5261
|
-
if isinstance(index, int):
|
5262
|
-
self.RI.tree[pid].children.insert(index, self.RI.tree[iid])
|
5263
|
-
else:
|
5264
|
-
self.RI.tree[pid].children.append(self.RI.tree[iid])
|
5265
5237
|
exclude = set()
|
5266
5238
|
if isinstance(iid_column, int) and not include_iid_column:
|
5267
5239
|
exclude.add(iid_column)
|
5268
5240
|
if isinstance(text_column, int) and not include_text_column:
|
5269
5241
|
exclude.add(text_column)
|
5270
5242
|
if exclude:
|
5271
|
-
to_insert.append([
|
5243
|
+
to_insert.append([new_node] + [e for c, e in enumerate(r) if c not in exclude])
|
5272
5244
|
else:
|
5273
|
-
to_insert.append([
|
5245
|
+
to_insert.append([new_node] + r)
|
5274
5246
|
rns_to_add[iid] = rn
|
5275
5247
|
self.insert_rows(
|
5276
5248
|
rows=to_insert,
|
@@ -5278,10 +5250,10 @@ class Sheet(tk.Frame):
|
|
5278
5250
|
row_index=True,
|
5279
5251
|
create_selections=create_selections,
|
5280
5252
|
fill=False,
|
5253
|
+
undo=undo,
|
5254
|
+
tree=True,
|
5281
5255
|
)
|
5282
|
-
|
5283
|
-
self.RI.tree_rns[iid] = rn
|
5284
|
-
if pid and (pid not in self.RI.tree_open_ids or not self.item_displayed(pid)):
|
5256
|
+
if parent and (parent not in self.RI.tree_open_ids or not self.item_displayed(parent)):
|
5285
5257
|
self.hide_rows(range(datarn, datarn + len(to_insert)), deselect_all=False, data_indexes=True)
|
5286
5258
|
return rns_to_add
|
5287
5259
|
|
@@ -5368,9 +5340,9 @@ class Sheet(tk.Frame):
|
|
5368
5340
|
elif item == "":
|
5369
5341
|
yield from map(attrgetter("iid"), self.RI.gen_top_nodes())
|
5370
5342
|
else:
|
5371
|
-
yield from
|
5343
|
+
yield from self.RI.tree[item].children
|
5372
5344
|
|
5373
|
-
def
|
5345
|
+
def get_iids(self, item: None | str = None) -> Generator[str]:
|
5374
5346
|
if item is None:
|
5375
5347
|
for n in self.RI.tree.values():
|
5376
5348
|
if not n.parent:
|
@@ -5379,31 +5351,16 @@ class Sheet(tk.Frame):
|
|
5379
5351
|
elif item == "":
|
5380
5352
|
yield from (n.iid for n in self.RI.tree.values() if not n.parent)
|
5381
5353
|
else:
|
5382
|
-
yield from
|
5354
|
+
yield from self.RI.tree[item].children
|
5383
5355
|
|
5384
|
-
def del_items(self, *items) -> Sheet:
|
5356
|
+
def del_items(self, *items, undo: bool = True) -> Sheet:
|
5385
5357
|
"""
|
5386
5358
|
Also deletes all descendants of items
|
5387
5359
|
"""
|
5388
|
-
|
5389
|
-
|
5390
|
-
|
5391
|
-
|
5392
|
-
continue
|
5393
|
-
rows_to_del.append(self.RI.tree_rns[item])
|
5394
|
-
iids_to_del.append(item)
|
5395
|
-
for did in self.RI.get_iid_descendants(item):
|
5396
|
-
rows_to_del.append(self.RI.tree_rns[did])
|
5397
|
-
iids_to_del.append(did)
|
5398
|
-
for item in unpack(items):
|
5399
|
-
self.RI.remove_node_from_parents_children(self.RI.tree[item])
|
5400
|
-
self.del_rows(rows_to_del)
|
5401
|
-
for iid in iids_to_del:
|
5402
|
-
self.RI.tree_open_ids.discard(iid)
|
5403
|
-
if self.RI.tree[iid].parent and len(self.RI.tree[iid].parent.children) == 1:
|
5404
|
-
self.RI.tree_open_ids.discard(self.RI.tree[iid].parent.iid)
|
5405
|
-
del self.RI.tree[iid]
|
5406
|
-
return self.set_refresh_timer()
|
5360
|
+
rows = list(map(self.RI.tree_rns.get, filter(self.exists, unpack(items))))
|
5361
|
+
if rows:
|
5362
|
+
self.del_rows(rows, data_indexes=True, undo=undo)
|
5363
|
+
return self.set_refresh_timer(rows)
|
5407
5364
|
|
5408
5365
|
def set_children(self, parent: str, *newchildren) -> Sheet:
|
5409
5366
|
"""
|
@@ -5419,123 +5376,42 @@ class Sheet(tk.Frame):
|
|
5419
5376
|
except Exception:
|
5420
5377
|
return None
|
5421
5378
|
|
5422
|
-
def move(
|
5379
|
+
def move(
|
5380
|
+
self,
|
5381
|
+
item: str,
|
5382
|
+
parent: str,
|
5383
|
+
index: int | None = None,
|
5384
|
+
select: bool = True,
|
5385
|
+
undo: bool = True,
|
5386
|
+
emit_event: bool = False,
|
5387
|
+
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
5423
5388
|
"""
|
5424
5389
|
Moves item to be under parent as child at index
|
5425
5390
|
'parent' can be an empty str which will put the item at top level
|
5426
|
-
Performance is not great
|
5427
5391
|
"""
|
5428
5392
|
if item not in self.RI.tree:
|
5429
5393
|
raise ValueError(f"Item '{item}' does not exist.")
|
5430
5394
|
if parent and parent not in self.RI.tree:
|
5431
5395
|
raise ValueError(f"Parent '{parent}' does not exist.")
|
5432
|
-
|
5433
|
-
|
5434
|
-
|
5435
|
-
|
5436
|
-
|
5437
|
-
|
5438
|
-
|
5439
|
-
|
5440
|
-
|
5441
|
-
|
5442
|
-
|
5443
|
-
|
5444
|
-
index = len(parent_node.children)
|
5445
|
-
new_r = self.RI.tree_rns[parent] + sum(1 for _ in self.RI.get_iid_descendants(parent))
|
5446
|
-
# new parent has children
|
5447
|
-
# index is on end
|
5448
|
-
# item row is less than move to row
|
5449
|
-
if item_r < new_r:
|
5450
|
-
r_ctr = new_r - num_item_descendants
|
5451
|
-
|
5452
|
-
# new parent has children
|
5453
|
-
# index is on end
|
5454
|
-
# item row is greater than move to row
|
5455
|
-
else:
|
5456
|
-
r_ctr = new_r + 1
|
5457
|
-
else:
|
5458
|
-
new_r = self.RI.tree_rns[parent_node.children[index].iid]
|
5459
|
-
# new parent has children
|
5460
|
-
# index is not end
|
5461
|
-
# item row is less than move to row
|
5462
|
-
if item_r < new_r:
|
5463
|
-
if self.RI.items_parent(item) == parent:
|
5464
|
-
r_ctr = (
|
5465
|
-
new_r
|
5466
|
-
+ sum(1 for _ in self.RI.get_iid_descendants(parent_node.children[index].iid))
|
5467
|
-
- num_item_descendants
|
5468
|
-
)
|
5469
|
-
else:
|
5470
|
-
r_ctr = new_r - num_item_descendants - 1
|
5471
|
-
|
5472
|
-
# new parent has children
|
5473
|
-
# index is not end
|
5474
|
-
# item row is greater than move to row
|
5475
|
-
else:
|
5476
|
-
r_ctr = new_r
|
5477
|
-
else:
|
5478
|
-
index = 0
|
5479
|
-
new_r = self.RI.tree_rns[parent_node.iid]
|
5480
|
-
|
5481
|
-
# new parent doesn't have children
|
5482
|
-
# index always start
|
5483
|
-
# item row is less than move to row
|
5484
|
-
if item_r < new_r:
|
5485
|
-
r_ctr = new_r - num_item_descendants
|
5486
|
-
|
5487
|
-
# new parent doesn't have children
|
5488
|
-
# index always start
|
5489
|
-
# item row is greater than move to row
|
5490
|
-
else:
|
5491
|
-
r_ctr = new_r + 1
|
5492
|
-
mapping[item_r] = r_ctr
|
5493
|
-
if parent in self.RI.tree_open_ids and self.item_displayed(parent):
|
5494
|
-
to_show.append(r_ctr)
|
5495
|
-
r_ctr += 1
|
5496
|
-
for did in item_descendants:
|
5497
|
-
mapping[self.RI.tree_rns[did]] = r_ctr
|
5498
|
-
if to_show and self.RI.ancestors_all_open(did, item_node.parent):
|
5499
|
-
to_show.append(r_ctr)
|
5500
|
-
r_ctr += 1
|
5501
|
-
if parent == self.RI.items_parent(item):
|
5502
|
-
pop_index = parent_node.children.index(item_node)
|
5503
|
-
parent_node.children.insert(index, parent_node.children.pop(pop_index))
|
5504
|
-
else:
|
5505
|
-
self.RI.remove_node_from_parents_children(item_node)
|
5506
|
-
item_node.parent = parent_node
|
5507
|
-
parent_node.children.insert(index, item_node)
|
5508
|
-
else:
|
5509
|
-
if index is None or (new_r := self.top_index_row(index)) is None:
|
5510
|
-
new_r = self.top_index_row(sum(1 for _ in self.RI.gen_top_nodes()) - 1)
|
5511
|
-
if item_r < new_r:
|
5512
|
-
r_ctr = (
|
5513
|
-
new_r
|
5514
|
-
+ sum(1 for _ in self.RI.get_iid_descendants(self.rowitem(new_r, data_index=True)))
|
5515
|
-
- num_item_descendants
|
5516
|
-
)
|
5517
|
-
else:
|
5518
|
-
r_ctr = new_r
|
5519
|
-
mapping[item_r] = r_ctr
|
5520
|
-
to_show.append(r_ctr)
|
5521
|
-
r_ctr += 1
|
5522
|
-
for did in item_descendants:
|
5523
|
-
mapping[self.RI.tree_rns[did]] = r_ctr
|
5524
|
-
if to_show and self.RI.ancestors_all_open(did, item_node.parent):
|
5525
|
-
to_show.append(r_ctr)
|
5526
|
-
r_ctr += 1
|
5527
|
-
self.RI.remove_node_from_parents_children(item_node)
|
5528
|
-
self.RI.tree[item].parent = ""
|
5529
|
-
self.mapping_move_rows(
|
5530
|
-
data_new_idxs=mapping,
|
5531
|
-
data_indexes=True,
|
5532
|
-
create_selections=False,
|
5533
|
-
redraw=False,
|
5396
|
+
if self.RI.move_pid_causes_recursive_loop(item, parent):
|
5397
|
+
raise ValueError(f"Item '{item}' causes recursive loop with parent '{parent}.")
|
5398
|
+
data_new_idxs, disp_new_idxs, event_data = self.MT.move_rows_adjust_options_dict(
|
5399
|
+
data_new_idxs={},
|
5400
|
+
data_old_idxs={},
|
5401
|
+
totalrows=None,
|
5402
|
+
disp_new_idxs={},
|
5403
|
+
move_data=True,
|
5404
|
+
move_heights=True,
|
5405
|
+
create_selections=select,
|
5406
|
+
event_data=None,
|
5407
|
+
node_change=(item, parent, index),
|
5534
5408
|
)
|
5535
|
-
if
|
5536
|
-
self.
|
5537
|
-
|
5538
|
-
|
5409
|
+
if undo:
|
5410
|
+
self.MT.undo_stack.append(stored_event_dict(event_data))
|
5411
|
+
if emit_event:
|
5412
|
+
self.emit_event("<<SheetModified>>", event_data)
|
5413
|
+
self.set_refresh_timer()
|
5414
|
+
return data_new_idxs, disp_new_idxs, event_data
|
5539
5415
|
|
5540
5416
|
reattach = move
|
5541
5417
|
|
@@ -5545,15 +5421,16 @@ class Sheet(tk.Frame):
|
|
5545
5421
|
def parent(self, item: str) -> str:
|
5546
5422
|
if item not in self.RI.tree:
|
5547
5423
|
raise ValueError(f"Item '{item}' does not exist.")
|
5548
|
-
return self.RI.tree[item].parent
|
5424
|
+
return self.RI.tree[item].parent
|
5549
5425
|
|
5550
5426
|
def index(self, item: str) -> int:
|
5551
5427
|
if item not in self.RI.tree:
|
5552
5428
|
raise ValueError(f"Item '{item}' does not exist.")
|
5553
|
-
|
5429
|
+
elif self.RI.tree[item].parent:
|
5430
|
+
return self.RI.parent_node(item).children.index(item)
|
5431
|
+
else:
|
5554
5432
|
find_node = self.RI.tree[item]
|
5555
5433
|
return next(index for index, node in enumerate(self.RI.gen_top_nodes()) if node == find_node)
|
5556
|
-
return self.RI.tree[item].parent.children.index(self.RI.tree[item])
|
5557
5434
|
|
5558
5435
|
def item_displayed(self, item: str) -> bool:
|
5559
5436
|
"""
|
@@ -5562,7 +5439,7 @@ class Sheet(tk.Frame):
|
|
5562
5439
|
"""
|
5563
5440
|
if item not in self.RI.tree:
|
5564
5441
|
raise ValueError(f"Item '{item}' does not exist.")
|
5565
|
-
return self.RI.tree_rns[item]
|
5442
|
+
return bisect_in(self.MT.displayed_rows, self.RI.tree_rns[item])
|
5566
5443
|
|
5567
5444
|
def display_item(self, item: str, redraw: bool = False) -> Sheet:
|
5568
5445
|
"""
|
@@ -5971,7 +5848,7 @@ class Sheet(tk.Frame):
|
|
5971
5848
|
def set_row_data(
|
5972
5849
|
self,
|
5973
5850
|
r: int,
|
5974
|
-
values=
|
5851
|
+
values: Sequence[object] = [],
|
5975
5852
|
add_columns: bool = True,
|
5976
5853
|
redraw: bool = True,
|
5977
5854
|
keep_formatting: bool = True,
|
@@ -5989,7 +5866,7 @@ class Sheet(tk.Frame):
|
|
5989
5866
|
if c > maxidx:
|
5990
5867
|
self.MT.data[r].append(v)
|
5991
5868
|
if self.MT.all_columns_displayed:
|
5992
|
-
self.MT.
|
5869
|
+
self.MT.insert_col_positions()
|
5993
5870
|
else:
|
5994
5871
|
self.set_cell_data(r=r, c=c, value=v, redraw=False, keep_formatting=keep_formatting)
|
5995
5872
|
else:
|
@@ -6003,7 +5880,7 @@ class Sheet(tk.Frame):
|
|
6003
5880
|
def set_column_data(
|
6004
5881
|
self,
|
6005
5882
|
c: int,
|
6006
|
-
values=
|
5883
|
+
values: Sequence[object] = [],
|
6007
5884
|
add_rows: bool = True,
|
6008
5885
|
redraw: bool = True,
|
6009
5886
|
keep_formatting: bool = True,
|
@@ -6020,7 +5897,7 @@ class Sheet(tk.Frame):
|
|
6020
5897
|
total_cols = self.MT.total_data_cols()
|
6021
5898
|
self.MT.fix_data_len(rn, total_cols - 1)
|
6022
5899
|
if self.MT.all_rows_displayed:
|
6023
|
-
self.MT.
|
5900
|
+
self.MT.insert_row_positions(heights=height)
|
6024
5901
|
maxidx += 1
|
6025
5902
|
if c >= len(self.MT.data[rn]):
|
6026
5903
|
self.MT.fix_row_len(rn, c)
|
@@ -7018,7 +6895,6 @@ class Sheet(tk.Frame):
|
|
7018
6895
|
self.RI.dropdown.window.values(values)
|
7019
6896
|
if set_value is not None:
|
7020
6897
|
self.MT.row_index(newindex=set_value, index=r_)
|
7021
|
-
# here
|
7022
6898
|
return self
|
7023
6899
|
|
7024
6900
|
def get_dropdown_values(self, r: int = 0, c: int = 0) -> None | list:
|
@@ -7248,7 +7124,7 @@ class Dropdown(Sheet):
|
|
7248
7124
|
modified_function: None | Callable = None,
|
7249
7125
|
arrowkey_RIGHT: Callable | None = None,
|
7250
7126
|
arrowkey_LEFT: Callable | None = None,
|
7251
|
-
align: str = "
|
7127
|
+
align: str = "nw",
|
7252
7128
|
# False for using r, c
|
7253
7129
|
# "r" for r
|
7254
7130
|
# "c" for c
|