tksheet 7.0.6__py3-none-any.whl → 7.1.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 +3 -3
- tksheet/column_headers.py +252 -270
- tksheet/functions.py +42 -9
- tksheet/main_table.py +779 -815
- tksheet/other_classes.py +129 -4
- tksheet/row_index.py +470 -316
- tksheet/sheet.py +994 -177
- tksheet/sheet_options.py +34 -0
- tksheet/text_editor.py +93 -78
- tksheet/themes.py +104 -0
- tksheet/vars.py +35 -0
- {tksheet-7.0.6.dist-info → tksheet-7.1.1.dist-info}/METADATA +1 -1
- tksheet-7.1.1.dist-info/RECORD +20 -0
- {tksheet-7.0.6.dist-info → tksheet-7.1.1.dist-info}/WHEEL +1 -1
- tksheet-7.0.6.dist-info/RECORD +0 -20
- {tksheet-7.0.6.dist-info → tksheet-7.1.1.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.0.6.dist-info → tksheet-7.1.1.dist-info}/top_level.txt +0 -0
tksheet/sheet.py
CHANGED
@@ -2,9 +2,10 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import tkinter as tk
|
4
4
|
from bisect import bisect_left
|
5
|
-
from collections import deque
|
5
|
+
from collections import defaultdict, deque
|
6
6
|
from collections.abc import Callable, Generator, Iterator, Sequence
|
7
7
|
from itertools import accumulate, chain, islice, product
|
8
|
+
from timeit import default_timer
|
8
9
|
from tkinter import ttk
|
9
10
|
from typing import Literal
|
10
11
|
from warnings import warn as WARNING
|
@@ -29,20 +30,23 @@ from .functions import (
|
|
29
30
|
is_iterable,
|
30
31
|
key_to_span,
|
31
32
|
num2alpha,
|
33
|
+
pop_positions,
|
32
34
|
set_align,
|
33
35
|
set_readonly,
|
34
36
|
span_froms,
|
35
37
|
span_ranges,
|
36
38
|
tksheet_type_error,
|
39
|
+
unpack,
|
37
40
|
)
|
38
41
|
from .main_table import MainTable
|
39
42
|
from .other_classes import (
|
40
|
-
CurrentlySelectedClass, # noqa: F401
|
41
43
|
DotDict,
|
42
44
|
EventDataDict,
|
43
45
|
FontTuple,
|
44
46
|
GeneratedMouseEvent,
|
47
|
+
Node,
|
45
48
|
Span,
|
49
|
+
Selected,
|
46
50
|
)
|
47
51
|
from .row_index import RowIndex
|
48
52
|
from .sheet_options import (
|
@@ -66,6 +70,7 @@ from .vars import (
|
|
66
70
|
emitted_events,
|
67
71
|
named_span_types,
|
68
72
|
rc_binding,
|
73
|
+
scrollbar_options_keys,
|
69
74
|
)
|
70
75
|
|
71
76
|
|
@@ -115,52 +120,6 @@ class Sheet(tk.Frame):
|
|
115
120
|
all_columns_displayed: bool = True,
|
116
121
|
displayed_rows: list[int] = [],
|
117
122
|
all_rows_displayed: bool = True,
|
118
|
-
outline_thickness: int = 0,
|
119
|
-
outline_color: str = theme_light_blue["outline_color"],
|
120
|
-
theme: str = "light blue",
|
121
|
-
frame_bg: str = theme_light_blue["table_bg"],
|
122
|
-
popup_menu_fg: str = theme_light_blue["popup_menu_fg"],
|
123
|
-
popup_menu_bg: str = theme_light_blue["popup_menu_bg"],
|
124
|
-
popup_menu_highlight_bg: str = theme_light_blue["popup_menu_highlight_bg"],
|
125
|
-
popup_menu_highlight_fg: str = theme_light_blue["popup_menu_highlight_fg"],
|
126
|
-
table_grid_fg: str = theme_light_blue["table_grid_fg"],
|
127
|
-
table_bg: str = theme_light_blue["table_bg"],
|
128
|
-
table_fg: str = theme_light_blue["table_fg"],
|
129
|
-
table_selected_box_cells_fg: str = theme_light_blue["table_selected_box_cells_fg"],
|
130
|
-
table_selected_box_rows_fg: str = theme_light_blue["table_selected_box_rows_fg"],
|
131
|
-
table_selected_box_columns_fg: str = theme_light_blue["table_selected_box_columns_fg"],
|
132
|
-
table_selected_cells_border_fg: str = theme_light_blue["table_selected_cells_border_fg"],
|
133
|
-
table_selected_cells_bg: str = theme_light_blue["table_selected_cells_bg"],
|
134
|
-
table_selected_cells_fg: str = theme_light_blue["table_selected_cells_fg"],
|
135
|
-
table_selected_rows_border_fg: str = theme_light_blue["table_selected_rows_border_fg"],
|
136
|
-
table_selected_rows_bg: str = theme_light_blue["table_selected_rows_bg"],
|
137
|
-
table_selected_rows_fg: str = theme_light_blue["table_selected_rows_fg"],
|
138
|
-
table_selected_columns_border_fg: str = theme_light_blue["table_selected_columns_border_fg"],
|
139
|
-
table_selected_columns_bg: str = theme_light_blue["table_selected_columns_bg"],
|
140
|
-
table_selected_columns_fg: str = theme_light_blue["table_selected_columns_fg"],
|
141
|
-
resizing_line_fg: str = theme_light_blue["resizing_line_fg"],
|
142
|
-
drag_and_drop_bg: str = theme_light_blue["drag_and_drop_bg"],
|
143
|
-
index_bg: str = theme_light_blue["index_bg"],
|
144
|
-
index_border_fg: str = theme_light_blue["index_border_fg"],
|
145
|
-
index_grid_fg: str = theme_light_blue["index_grid_fg"],
|
146
|
-
index_fg: str = theme_light_blue["index_fg"],
|
147
|
-
index_selected_cells_bg: str = theme_light_blue["index_selected_cells_bg"],
|
148
|
-
index_selected_cells_fg: str = theme_light_blue["index_selected_cells_fg"],
|
149
|
-
index_selected_rows_bg: str = theme_light_blue["index_selected_rows_bg"],
|
150
|
-
index_selected_rows_fg: str = theme_light_blue["index_selected_rows_fg"],
|
151
|
-
index_hidden_rows_expander_bg: str = theme_light_blue["index_hidden_rows_expander_bg"],
|
152
|
-
header_bg: str = theme_light_blue["header_bg"],
|
153
|
-
header_border_fg: str = theme_light_blue["header_border_fg"],
|
154
|
-
header_grid_fg: str = theme_light_blue["header_grid_fg"],
|
155
|
-
header_fg: str = theme_light_blue["header_fg"],
|
156
|
-
header_selected_cells_bg: str = theme_light_blue["header_selected_cells_bg"],
|
157
|
-
header_selected_cells_fg: str = theme_light_blue["header_selected_cells_fg"],
|
158
|
-
header_selected_columns_bg: str = theme_light_blue["header_selected_columns_bg"],
|
159
|
-
header_selected_columns_fg: str = theme_light_blue["header_selected_columns_fg"],
|
160
|
-
header_hidden_columns_expander_bg: str = theme_light_blue["header_hidden_columns_expander_bg"],
|
161
|
-
top_left_bg: str = theme_light_blue["top_left_bg"],
|
162
|
-
top_left_fg: str = theme_light_blue["top_left_fg"],
|
163
|
-
top_left_fg_highlight: str = theme_light_blue["top_left_fg_highlight"],
|
164
123
|
to_clipboard_delimiter: str = "\t",
|
165
124
|
to_clipboard_quotechar: str = '"',
|
166
125
|
to_clipboard_lineterminator: str = "\n",
|
@@ -174,7 +133,7 @@ class Sheet(tk.Frame):
|
|
174
133
|
show_dropdown_borders: bool = False,
|
175
134
|
arrow_key_down_right_scroll_page: bool = False,
|
176
135
|
cell_auto_resize_enabled: bool = True,
|
177
|
-
auto_resize_row_index: bool =
|
136
|
+
auto_resize_row_index: bool | Literal["empty"] = "empty",
|
178
137
|
auto_resize_columns: int | None = None,
|
179
138
|
auto_resize_rows: int | None = None,
|
180
139
|
set_cell_sizes_on_zoom: bool = False,
|
@@ -210,6 +169,91 @@ class Sheet(tk.Frame):
|
|
210
169
|
show_horizontal_grid: bool = True,
|
211
170
|
display_selected_fg_over_highlights: bool = False,
|
212
171
|
show_selected_cells_border: bool = True,
|
172
|
+
treeview: bool = False,
|
173
|
+
# colors
|
174
|
+
outline_thickness: int = 0,
|
175
|
+
outline_color: str = theme_light_blue["outline_color"],
|
176
|
+
theme: str = "light blue",
|
177
|
+
frame_bg: str = theme_light_blue["table_bg"],
|
178
|
+
popup_menu_fg: str = theme_light_blue["popup_menu_fg"],
|
179
|
+
popup_menu_bg: str = theme_light_blue["popup_menu_bg"],
|
180
|
+
popup_menu_highlight_bg: str = theme_light_blue["popup_menu_highlight_bg"],
|
181
|
+
popup_menu_highlight_fg: str = theme_light_blue["popup_menu_highlight_fg"],
|
182
|
+
table_grid_fg: str = theme_light_blue["table_grid_fg"],
|
183
|
+
table_bg: str = theme_light_blue["table_bg"],
|
184
|
+
table_fg: str = theme_light_blue["table_fg"],
|
185
|
+
table_selected_box_cells_fg: str = theme_light_blue["table_selected_box_cells_fg"],
|
186
|
+
table_selected_box_rows_fg: str = theme_light_blue["table_selected_box_rows_fg"],
|
187
|
+
table_selected_box_columns_fg: str = theme_light_blue["table_selected_box_columns_fg"],
|
188
|
+
table_selected_cells_border_fg: str = theme_light_blue["table_selected_cells_border_fg"],
|
189
|
+
table_selected_cells_bg: str = theme_light_blue["table_selected_cells_bg"],
|
190
|
+
table_selected_cells_fg: str = theme_light_blue["table_selected_cells_fg"],
|
191
|
+
table_selected_rows_border_fg: str = theme_light_blue["table_selected_rows_border_fg"],
|
192
|
+
table_selected_rows_bg: str = theme_light_blue["table_selected_rows_bg"],
|
193
|
+
table_selected_rows_fg: str = theme_light_blue["table_selected_rows_fg"],
|
194
|
+
table_selected_columns_border_fg: str = theme_light_blue["table_selected_columns_border_fg"],
|
195
|
+
table_selected_columns_bg: str = theme_light_blue["table_selected_columns_bg"],
|
196
|
+
table_selected_columns_fg: str = theme_light_blue["table_selected_columns_fg"],
|
197
|
+
resizing_line_fg: str = theme_light_blue["resizing_line_fg"],
|
198
|
+
drag_and_drop_bg: str = theme_light_blue["drag_and_drop_bg"],
|
199
|
+
index_bg: str = theme_light_blue["index_bg"],
|
200
|
+
index_border_fg: str = theme_light_blue["index_border_fg"],
|
201
|
+
index_grid_fg: str = theme_light_blue["index_grid_fg"],
|
202
|
+
index_fg: str = theme_light_blue["index_fg"],
|
203
|
+
index_selected_cells_bg: str = theme_light_blue["index_selected_cells_bg"],
|
204
|
+
index_selected_cells_fg: str = theme_light_blue["index_selected_cells_fg"],
|
205
|
+
index_selected_rows_bg: str = theme_light_blue["index_selected_rows_bg"],
|
206
|
+
index_selected_rows_fg: str = theme_light_blue["index_selected_rows_fg"],
|
207
|
+
index_hidden_rows_expander_bg: str = theme_light_blue["index_hidden_rows_expander_bg"],
|
208
|
+
header_bg: str = theme_light_blue["header_bg"],
|
209
|
+
header_border_fg: str = theme_light_blue["header_border_fg"],
|
210
|
+
header_grid_fg: str = theme_light_blue["header_grid_fg"],
|
211
|
+
header_fg: str = theme_light_blue["header_fg"],
|
212
|
+
header_selected_cells_bg: str = theme_light_blue["header_selected_cells_bg"],
|
213
|
+
header_selected_cells_fg: str = theme_light_blue["header_selected_cells_fg"],
|
214
|
+
header_selected_columns_bg: str = theme_light_blue["header_selected_columns_bg"],
|
215
|
+
header_selected_columns_fg: str = theme_light_blue["header_selected_columns_fg"],
|
216
|
+
header_hidden_columns_expander_bg: str = theme_light_blue["header_hidden_columns_expander_bg"],
|
217
|
+
top_left_bg: str = theme_light_blue["top_left_bg"],
|
218
|
+
top_left_fg: str = theme_light_blue["top_left_fg"],
|
219
|
+
top_left_fg_highlight: str = theme_light_blue["top_left_fg_highlight"],
|
220
|
+
vertical_scroll_background: str = theme_light_blue["vertical_scroll_background"],
|
221
|
+
horizontal_scroll_background: str = theme_light_blue["horizontal_scroll_background"],
|
222
|
+
vertical_scroll_troughcolor: str = theme_light_blue["vertical_scroll_troughcolor"],
|
223
|
+
horizontal_scroll_troughcolor: str = theme_light_blue["horizontal_scroll_troughcolor"],
|
224
|
+
vertical_scroll_lightcolor: str = theme_light_blue["vertical_scroll_lightcolor"],
|
225
|
+
horizontal_scroll_lightcolor: str = theme_light_blue["horizontal_scroll_lightcolor"],
|
226
|
+
vertical_scroll_darkcolor: str = theme_light_blue["vertical_scroll_darkcolor"],
|
227
|
+
horizontal_scroll_darkcolor: str = theme_light_blue["horizontal_scroll_darkcolor"],
|
228
|
+
vertical_scroll_relief: str = theme_light_blue["vertical_scroll_relief"],
|
229
|
+
horizontal_scroll_relief: str = theme_light_blue["horizontal_scroll_relief"],
|
230
|
+
vertical_scroll_troughrelief: str = theme_light_blue["vertical_scroll_troughrelief"],
|
231
|
+
horizontal_scroll_troughrelief: str = theme_light_blue["horizontal_scroll_troughrelief"],
|
232
|
+
vertical_scroll_bordercolor: str = theme_light_blue["vertical_scroll_bordercolor"],
|
233
|
+
horizontal_scroll_bordercolor: str = theme_light_blue["horizontal_scroll_bordercolor"],
|
234
|
+
vertical_scroll_borderwidth: int = 1,
|
235
|
+
horizontal_scroll_borderwidth: int = 1,
|
236
|
+
vertical_scroll_gripcount: int = 0,
|
237
|
+
horizontal_scroll_gripcount: int = 0,
|
238
|
+
vertical_scroll_active_bg: str = theme_light_blue["vertical_scroll_active_bg"],
|
239
|
+
horizontal_scroll_active_bg: str = theme_light_blue["horizontal_scroll_active_bg"],
|
240
|
+
vertical_scroll_not_active_bg: str = theme_light_blue["vertical_scroll_not_active_bg"],
|
241
|
+
horizontal_scroll_not_active_bg: str = theme_light_blue["horizontal_scroll_not_active_bg"],
|
242
|
+
vertical_scroll_pressed_bg: str = theme_light_blue["vertical_scroll_pressed_bg"],
|
243
|
+
horizontal_scroll_pressed_bg: str = theme_light_blue["horizontal_scroll_pressed_bg"],
|
244
|
+
vertical_scroll_active_fg: str = theme_light_blue["vertical_scroll_active_fg"],
|
245
|
+
horizontal_scroll_active_fg: str = theme_light_blue["horizontal_scroll_active_fg"],
|
246
|
+
vertical_scroll_not_active_fg: str = theme_light_blue["vertical_scroll_not_active_fg"],
|
247
|
+
horizontal_scroll_not_active_fg: str = theme_light_blue["horizontal_scroll_not_active_fg"],
|
248
|
+
vertical_scroll_pressed_fg: str = theme_light_blue["vertical_scroll_pressed_fg"],
|
249
|
+
horizontal_scroll_pressed_fg: str = theme_light_blue["horizontal_scroll_pressed_fg"],
|
250
|
+
scrollbar_theme_inheritance: str = "default",
|
251
|
+
scrollbar_show_arrows: bool = True,
|
252
|
+
# changing the arrowsize (width) of the scrollbars
|
253
|
+
# is not working with 'default' theme
|
254
|
+
# use 'clam' theme instead if you want to change the width
|
255
|
+
vertical_scroll_arrowsize: str | int = "",
|
256
|
+
horizontal_scroll_arrowsize: str | int = "",
|
213
257
|
# backwards compatibility
|
214
258
|
column_width: int | None = None,
|
215
259
|
header_height: str | int | None = None,
|
@@ -236,6 +280,9 @@ class Sheet(tk.Frame):
|
|
236
280
|
default_row_height = row_height
|
237
281
|
if row_index_width is not None:
|
238
282
|
default_row_index_width = row_index_width
|
283
|
+
if treeview:
|
284
|
+
index_align = "w"
|
285
|
+
auto_resize_row_index = True
|
239
286
|
for k, v in locals().items():
|
240
287
|
if (xk := backwards_compatibility_keys.get(k, k)) in self.ops and v != self.ops[xk]:
|
241
288
|
self.ops[xk] = v
|
@@ -306,8 +353,64 @@ class Sheet(tk.Frame):
|
|
306
353
|
row_index_canvas=self.RI,
|
307
354
|
header_canvas=self.CH,
|
308
355
|
)
|
309
|
-
self.
|
310
|
-
|
356
|
+
self.unique_id = f"{default_timer()}{self.winfo_id()}".replace(".", "")
|
357
|
+
style = ttk.Style()
|
358
|
+
for orientation in ("Vertical", "Horizontal"):
|
359
|
+
style.element_create(
|
360
|
+
f"Sheet{self.unique_id}.{orientation}.TScrollbar.trough",
|
361
|
+
"from",
|
362
|
+
scrollbar_theme_inheritance,
|
363
|
+
)
|
364
|
+
style.element_create(
|
365
|
+
f"Sheet{self.unique_id}.{orientation}.TScrollbar.thumb",
|
366
|
+
"from",
|
367
|
+
scrollbar_theme_inheritance,
|
368
|
+
)
|
369
|
+
style.element_create(
|
370
|
+
f"Sheet{self.unique_id}.{orientation}.TScrollbar.grip",
|
371
|
+
"from",
|
372
|
+
scrollbar_theme_inheritance,
|
373
|
+
)
|
374
|
+
if not scrollbar_show_arrows:
|
375
|
+
style.layout(
|
376
|
+
f"Sheet{self.unique_id}.{orientation}.TScrollbar",
|
377
|
+
[
|
378
|
+
(
|
379
|
+
f"Sheet{self.unique_id}.{orientation}.TScrollbar.trough",
|
380
|
+
{
|
381
|
+
"children": [
|
382
|
+
(
|
383
|
+
f"Sheet{self.unique_id}.{orientation}.TScrollbar.thumb",
|
384
|
+
{
|
385
|
+
"unit": "1",
|
386
|
+
"children": [
|
387
|
+
(
|
388
|
+
f"Sheet{self.unique_id}.{orientation}.TScrollbar.grip",
|
389
|
+
{"sticky": ""},
|
390
|
+
)
|
391
|
+
],
|
392
|
+
"sticky": "nswe",
|
393
|
+
},
|
394
|
+
)
|
395
|
+
],
|
396
|
+
"sticky": "ns" if orientation == "Vertical" else "ew",
|
397
|
+
},
|
398
|
+
)
|
399
|
+
],
|
400
|
+
)
|
401
|
+
self.set_scrollbar_options()
|
402
|
+
self.yscroll = ttk.Scrollbar(
|
403
|
+
self,
|
404
|
+
command=self.MT.set_yviews,
|
405
|
+
orient="vertical",
|
406
|
+
style=f"Sheet{self.unique_id}.Vertical.TScrollbar",
|
407
|
+
)
|
408
|
+
self.xscroll = ttk.Scrollbar(
|
409
|
+
self,
|
410
|
+
command=self.MT.set_xviews,
|
411
|
+
orient="horizontal",
|
412
|
+
style=f"Sheet{self.unique_id}.Horizontal.TScrollbar",
|
413
|
+
)
|
311
414
|
if show_top_left:
|
312
415
|
self.TL.grid(row=0, column=0)
|
313
416
|
if show_table:
|
@@ -1343,9 +1446,11 @@ class Sheet(tk.Frame):
|
|
1343
1446
|
row_heights: bool = True,
|
1344
1447
|
column_widths: bool = True,
|
1345
1448
|
cell_options: bool = True,
|
1449
|
+
tags: bool = True,
|
1346
1450
|
undo_stack: bool = True,
|
1347
1451
|
selections: bool = True,
|
1348
1452
|
sheet_options: bool = False,
|
1453
|
+
tree: bool = True,
|
1349
1454
|
redraw: bool = True,
|
1350
1455
|
) -> Sheet:
|
1351
1456
|
if table:
|
@@ -1355,17 +1460,23 @@ class Sheet(tk.Frame):
|
|
1355
1460
|
if index:
|
1356
1461
|
self.MT._row_index = []
|
1357
1462
|
if row_heights:
|
1463
|
+
self.MT.saved_row_heights = {}
|
1358
1464
|
self.MT.set_row_positions([])
|
1359
1465
|
if column_widths:
|
1466
|
+
self.MT.saved_column_widths = {}
|
1360
1467
|
self.MT.set_col_positions([])
|
1361
1468
|
if cell_options:
|
1362
1469
|
self.reset_all_options()
|
1470
|
+
if tags:
|
1471
|
+
self.MT.reset_tags()
|
1363
1472
|
if undo_stack:
|
1364
1473
|
self.reset_undos()
|
1365
1474
|
if selections:
|
1366
1475
|
self.MT.deselect(redraw=False)
|
1367
1476
|
if sheet_options:
|
1368
1477
|
self.ops = new_sheet_options()
|
1478
|
+
if tree:
|
1479
|
+
self.RI.reset_tree()
|
1369
1480
|
self.set_refresh_timer(redraw)
|
1370
1481
|
return self
|
1371
1482
|
|
@@ -1470,7 +1581,7 @@ class Sheet(tk.Frame):
|
|
1470
1581
|
event_data = event_dict(
|
1471
1582
|
name="edit_table",
|
1472
1583
|
sheet=self.name,
|
1473
|
-
selected=self.MT.
|
1584
|
+
selected=self.MT.selected,
|
1474
1585
|
)
|
1475
1586
|
set_t = self.event_data_set_table_cell
|
1476
1587
|
set_i, set_h = self.event_data_set_index_cell, self.event_data_set_header_cell
|
@@ -1700,7 +1811,7 @@ class Sheet(tk.Frame):
|
|
1700
1811
|
event_data = event_dict(
|
1701
1812
|
name="edit_table",
|
1702
1813
|
sheet=self.name,
|
1703
|
-
selected=self.MT.
|
1814
|
+
selected=self.MT.selected,
|
1704
1815
|
)
|
1705
1816
|
if index:
|
1706
1817
|
for r in rows:
|
@@ -1811,6 +1922,7 @@ class Sheet(tk.Frame):
|
|
1811
1922
|
fill: bool = True,
|
1812
1923
|
undo: bool = False,
|
1813
1924
|
emit_event: bool = False,
|
1925
|
+
create_selections: bool = True,
|
1814
1926
|
redraw: bool = True,
|
1815
1927
|
) -> EventDataDict:
|
1816
1928
|
total_cols = None
|
@@ -1873,8 +1985,9 @@ class Sheet(tk.Frame):
|
|
1873
1985
|
name="add_rows",
|
1874
1986
|
sheet=self.name,
|
1875
1987
|
boxes=self.MT.get_boxes(),
|
1876
|
-
selected=self.MT.
|
1988
|
+
selected=self.MT.selected,
|
1877
1989
|
),
|
1990
|
+
create_selections=create_selections,
|
1878
1991
|
)
|
1879
1992
|
if undo:
|
1880
1993
|
self.MT.undo_stack.append(ev_stack_dict(event_data))
|
@@ -1892,6 +2005,7 @@ class Sheet(tk.Frame):
|
|
1892
2005
|
fill: bool = True,
|
1893
2006
|
undo: bool = False,
|
1894
2007
|
emit_event: bool = False,
|
2008
|
+
create_selections: bool = True,
|
1895
2009
|
redraw: bool = True,
|
1896
2010
|
) -> EventDataDict:
|
1897
2011
|
old_total = self.MT.equalize_data_row_lengths()
|
@@ -1962,8 +2076,9 @@ class Sheet(tk.Frame):
|
|
1962
2076
|
name="add_columns",
|
1963
2077
|
sheet=self.name,
|
1964
2078
|
boxes=self.MT.get_boxes(),
|
1965
|
-
selected=self.MT.
|
2079
|
+
selected=self.MT.selected,
|
1966
2080
|
),
|
2081
|
+
create_selections=create_selections,
|
1967
2082
|
)
|
1968
2083
|
if undo:
|
1969
2084
|
self.MT.undo_stack.append(ev_stack_dict(event_data))
|
@@ -2021,7 +2136,7 @@ class Sheet(tk.Frame):
|
|
2021
2136
|
name="delete_rows",
|
2022
2137
|
sheet=self.name,
|
2023
2138
|
boxes=self.MT.get_boxes(),
|
2024
|
-
selected=self.MT.
|
2139
|
+
selected=self.MT.selected,
|
2025
2140
|
)
|
2026
2141
|
if not data_indexes:
|
2027
2142
|
event_data = self.MT.delete_rows_displayed(rows, event_data)
|
@@ -2062,7 +2177,7 @@ class Sheet(tk.Frame):
|
|
2062
2177
|
name="delete_columns",
|
2063
2178
|
sheet=self.name,
|
2064
2179
|
boxes=self.MT.get_boxes(),
|
2065
|
-
selected=self.MT.
|
2180
|
+
selected=self.MT.selected,
|
2066
2181
|
)
|
2067
2182
|
if not data_indexes:
|
2068
2183
|
event_data = self.MT.delete_columns_displayed(columns, event_data)
|
@@ -2257,7 +2372,7 @@ class Sheet(tk.Frame):
|
|
2257
2372
|
data_idxs, disp_idxs, event_data = self.MT.move_rows_adjust_options_dict(
|
2258
2373
|
data_new_idxs=data_new_idxs,
|
2259
2374
|
data_old_idxs=dict(zip(data_new_idxs.values(), data_new_idxs)),
|
2260
|
-
|
2375
|
+
totalrows=None,
|
2261
2376
|
disp_new_idxs=disp_new_idxs,
|
2262
2377
|
move_data=move_data,
|
2263
2378
|
create_selections=create_selections,
|
@@ -2401,11 +2516,11 @@ class Sheet(tk.Frame):
|
|
2401
2516
|
) -> Span:
|
2402
2517
|
span = self.span_from_key(*key)
|
2403
2518
|
if span.table:
|
2404
|
-
self.MT.
|
2519
|
+
self.MT.hide_dropdown_window()
|
2405
2520
|
if span.index:
|
2406
|
-
self.RI.
|
2521
|
+
self.RI.hide_dropdown_window()
|
2407
2522
|
if span.header:
|
2408
|
-
self.CH.
|
2523
|
+
self.CH.hide_dropdown_window()
|
2409
2524
|
self.del_options_using_span(span, "dropdown")
|
2410
2525
|
self.set_refresh_timer(redraw)
|
2411
2526
|
return span
|
@@ -2792,8 +2907,14 @@ class Sheet(tk.Frame):
|
|
2792
2907
|
|
2793
2908
|
# Getting Selected Cells
|
2794
2909
|
|
2795
|
-
def get_currently_selected(self) -> tuple[()] |
|
2796
|
-
|
2910
|
+
def get_currently_selected(self) -> tuple[()] | Selected:
|
2911
|
+
# if self.MT.selected:
|
2912
|
+
# return self.MT.selected._replace(type_=self.MT.selected.type_[:-1])
|
2913
|
+
return self.MT.selected
|
2914
|
+
|
2915
|
+
@property
|
2916
|
+
def selected(self) -> tuple[()] | Selected:
|
2917
|
+
return self.MT.selected
|
2797
2918
|
|
2798
2919
|
def get_selected_rows(
|
2799
2920
|
self,
|
@@ -3179,7 +3300,7 @@ class Sheet(tk.Frame):
|
|
3179
3300
|
canvas_positions: bool = False,
|
3180
3301
|
reset: bool = False,
|
3181
3302
|
) -> Sheet:
|
3182
|
-
if reset:
|
3303
|
+
if reset or column_widths is None:
|
3183
3304
|
self.MT.reset_col_positions()
|
3184
3305
|
elif is_iterable(column_widths):
|
3185
3306
|
if canvas_positions and isinstance(column_widths, list):
|
@@ -3194,9 +3315,9 @@ class Sheet(tk.Frame):
|
|
3194
3315
|
canvas_positions: bool = False,
|
3195
3316
|
reset: bool = False,
|
3196
3317
|
) -> Sheet:
|
3197
|
-
if reset:
|
3318
|
+
if reset or row_heights is None:
|
3198
3319
|
self.MT.reset_row_positions()
|
3199
|
-
|
3320
|
+
elif is_iterable(row_heights):
|
3200
3321
|
if canvas_positions and isinstance(row_heights, list):
|
3201
3322
|
self.MT.row_positions = row_heights
|
3202
3323
|
else:
|
@@ -3447,15 +3568,25 @@ class Sheet(tk.Frame):
|
|
3447
3568
|
def cell_completely_visible(self, r: int, c: int, seperate_axes: bool = False) -> bool:
|
3448
3569
|
return self.MT.cell_completely_visible(r, c, seperate_axes)
|
3449
3570
|
|
3450
|
-
def set_xview(self, position: float, option: str = "moveto") -> Sheet:
|
3451
|
-
|
3452
|
-
|
3571
|
+
def set_xview(self, position: None | float = None, option: str = "moveto") -> Sheet | tuple[float, float]:
|
3572
|
+
if position is not None:
|
3573
|
+
self.MT.set_xviews(option, position)
|
3574
|
+
return self
|
3575
|
+
return self.MT.xview()
|
3453
3576
|
|
3454
|
-
|
3455
|
-
|
3456
|
-
|
3577
|
+
xview = set_xview
|
3578
|
+
xview_moveto = set_xview
|
3579
|
+
|
3580
|
+
def set_yview(self, position: None | float = None, option: str = "moveto") -> Sheet | tuple[float, float]:
|
3581
|
+
if position is not None:
|
3582
|
+
self.MT.set_yviews(option, position)
|
3583
|
+
return self
|
3584
|
+
return self.MT.yview()
|
3585
|
+
|
3586
|
+
yview = set_yview
|
3587
|
+
yview_moveto = set_yview
|
3457
3588
|
|
3458
|
-
def set_view(self, x_args: [str, float], y_args: [str, float]) -> Sheet:
|
3589
|
+
def set_view(self, x_args: list[str, float], y_args: list[str, float]) -> Sheet:
|
3459
3590
|
self.MT.set_view(x_args, y_args)
|
3460
3591
|
return self
|
3461
3592
|
|
@@ -3470,6 +3601,8 @@ class Sheet(tk.Frame):
|
|
3470
3601
|
def displayed_column_to_data(self, c: int) -> int:
|
3471
3602
|
return c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
|
3472
3603
|
|
3604
|
+
data_c = displayed_column_to_data
|
3605
|
+
|
3473
3606
|
def display_columns(
|
3474
3607
|
self,
|
3475
3608
|
columns: None | Literal["all"] | Iterator[int] = None,
|
@@ -3494,31 +3627,70 @@ class Sheet(tk.Frame):
|
|
3494
3627
|
self.set_refresh_timer(redraw if redraw else refresh)
|
3495
3628
|
return res
|
3496
3629
|
|
3497
|
-
# uses displayed indexes
|
3498
3630
|
def hide_columns(
|
3499
3631
|
self,
|
3500
|
-
columns: int | set | Iterator[int]
|
3632
|
+
columns: int | set[int] | Iterator[int],
|
3501
3633
|
redraw: bool = True,
|
3502
3634
|
deselect_all: bool = True,
|
3635
|
+
data_indexes: bool = False,
|
3503
3636
|
) -> Sheet:
|
3504
3637
|
if isinstance(columns, int):
|
3505
|
-
|
3506
|
-
elif isinstance(columns, set):
|
3507
|
-
|
3508
|
-
|
3509
|
-
|
3510
|
-
if not _columns:
|
3511
|
-
return
|
3638
|
+
columns = {columns}
|
3639
|
+
elif not isinstance(columns, set):
|
3640
|
+
columns = set(columns)
|
3641
|
+
if not columns:
|
3642
|
+
return
|
3512
3643
|
if self.MT.all_columns_displayed:
|
3513
|
-
|
3644
|
+
self.MT.displayed_columns = [c for c in range(self.MT.total_data_cols()) if c not in columns]
|
3645
|
+
to_pop = {c: c for c in columns}
|
3514
3646
|
else:
|
3515
|
-
|
3516
|
-
|
3517
|
-
|
3518
|
-
|
3519
|
-
|
3520
|
-
|
3647
|
+
to_pop = {}
|
3648
|
+
new_disp = []
|
3649
|
+
if data_indexes:
|
3650
|
+
for i, c in enumerate(self.MT.displayed_columns):
|
3651
|
+
if c not in columns:
|
3652
|
+
new_disp.append(c)
|
3653
|
+
else:
|
3654
|
+
to_pop[i] = c
|
3655
|
+
else:
|
3656
|
+
for i, c in enumerate(self.MT.displayed_columns):
|
3657
|
+
if i not in columns:
|
3658
|
+
new_disp.append(c)
|
3659
|
+
else:
|
3660
|
+
to_pop[i] = c
|
3661
|
+
self.MT.displayed_columns = new_disp
|
3662
|
+
self.MT.all_columns_displayed = False
|
3663
|
+
self.MT.set_col_positions(
|
3664
|
+
pop_positions(
|
3665
|
+
itr=self.MT.gen_column_widths,
|
3666
|
+
to_pop=to_pop,
|
3667
|
+
save_to=self.MT.saved_column_widths,
|
3668
|
+
),
|
3521
3669
|
)
|
3670
|
+
if deselect_all:
|
3671
|
+
self.MT.deselect(redraw=False)
|
3672
|
+
self.set_refresh_timer(redraw)
|
3673
|
+
return self
|
3674
|
+
|
3675
|
+
# uses data indexes
|
3676
|
+
def show_columns(
|
3677
|
+
self,
|
3678
|
+
columns: int | Iterator[int],
|
3679
|
+
redraw: bool = True,
|
3680
|
+
deselect_all: bool = True,
|
3681
|
+
) -> Sheet:
|
3682
|
+
if isinstance(columns, int):
|
3683
|
+
columns = [columns]
|
3684
|
+
cws = self.MT.get_column_widths()
|
3685
|
+
for column in columns:
|
3686
|
+
idx = bisect_left(self.MT.displayed_columns, column)
|
3687
|
+
if len(self.MT.displayed_columns) == idx or self.MT.displayed_columns[idx] != column:
|
3688
|
+
self.MT.displayed_columns.insert(idx, column)
|
3689
|
+
cws.insert(idx, self.MT.saved_column_widths.pop(column, self.PAR.ops.default_column_width))
|
3690
|
+
self.MT.set_col_positions(cws)
|
3691
|
+
if deselect_all:
|
3692
|
+
self.MT.deselect(redraw=False)
|
3693
|
+
self.set_refresh_timer(redraw)
|
3522
3694
|
return self
|
3523
3695
|
|
3524
3696
|
def all_columns_displayed(self, a: bool | None = None) -> bool:
|
@@ -3536,6 +3708,8 @@ class Sheet(tk.Frame):
|
|
3536
3708
|
def displayed_row_to_data(self, r: int) -> int:
|
3537
3709
|
return r if self.MT.all_rows_displayed else self.MT.displayed_rows[r]
|
3538
3710
|
|
3711
|
+
data_r = displayed_row_to_data
|
3712
|
+
|
3539
3713
|
def display_rows(
|
3540
3714
|
self,
|
3541
3715
|
rows: None | Literal["all"] | Iterator[int] = None,
|
@@ -3558,31 +3732,70 @@ class Sheet(tk.Frame):
|
|
3558
3732
|
self.set_refresh_timer(redraw if redraw else refresh)
|
3559
3733
|
return res
|
3560
3734
|
|
3561
|
-
# uses displayed indexes
|
3562
3735
|
def hide_rows(
|
3563
3736
|
self,
|
3564
|
-
rows: int | set | Iterator[int]
|
3737
|
+
rows: int | set[int] | Iterator[int],
|
3565
3738
|
redraw: bool = True,
|
3566
3739
|
deselect_all: bool = True,
|
3740
|
+
data_indexes: bool = False,
|
3567
3741
|
) -> Sheet:
|
3568
3742
|
if isinstance(rows, int):
|
3569
|
-
|
3570
|
-
elif isinstance(rows, set):
|
3571
|
-
|
3572
|
-
|
3573
|
-
|
3574
|
-
if not _rows:
|
3575
|
-
return
|
3743
|
+
rows = {rows}
|
3744
|
+
elif not isinstance(rows, set):
|
3745
|
+
rows = set(rows)
|
3746
|
+
if not rows:
|
3747
|
+
return
|
3576
3748
|
if self.MT.all_rows_displayed:
|
3577
|
-
|
3749
|
+
self.MT.displayed_rows = [r for r in range(self.MT.total_data_rows()) if r not in rows]
|
3750
|
+
to_pop = {r: r for r in rows}
|
3578
3751
|
else:
|
3579
|
-
|
3580
|
-
|
3581
|
-
|
3582
|
-
|
3583
|
-
|
3584
|
-
|
3752
|
+
to_pop = {}
|
3753
|
+
new_disp = []
|
3754
|
+
if data_indexes:
|
3755
|
+
for i, r in enumerate(self.MT.displayed_rows):
|
3756
|
+
if r not in rows:
|
3757
|
+
new_disp.append(r)
|
3758
|
+
else:
|
3759
|
+
to_pop[i] = r
|
3760
|
+
else:
|
3761
|
+
for i, r in enumerate(self.MT.displayed_rows):
|
3762
|
+
if i not in rows:
|
3763
|
+
new_disp.append(r)
|
3764
|
+
else:
|
3765
|
+
to_pop[i] = r
|
3766
|
+
self.MT.displayed_rows = new_disp
|
3767
|
+
self.MT.all_rows_displayed = False
|
3768
|
+
self.MT.set_row_positions(
|
3769
|
+
pop_positions(
|
3770
|
+
itr=self.MT.gen_row_heights,
|
3771
|
+
to_pop=to_pop,
|
3772
|
+
save_to=self.MT.saved_row_heights,
|
3773
|
+
),
|
3585
3774
|
)
|
3775
|
+
if deselect_all:
|
3776
|
+
self.MT.deselect(redraw=False)
|
3777
|
+
self.set_refresh_timer(redraw)
|
3778
|
+
return self
|
3779
|
+
|
3780
|
+
# uses data indexes
|
3781
|
+
def show_rows(
|
3782
|
+
self,
|
3783
|
+
rows: int | Iterator[int],
|
3784
|
+
redraw: bool = True,
|
3785
|
+
deselect_all: bool = True,
|
3786
|
+
) -> Sheet:
|
3787
|
+
if isinstance(rows, int):
|
3788
|
+
rows = [rows]
|
3789
|
+
rhs = self.MT.get_row_heights()
|
3790
|
+
for row in rows:
|
3791
|
+
idx = bisect_left(self.MT.displayed_rows, row)
|
3792
|
+
if len(self.MT.displayed_rows) == idx or self.MT.displayed_rows[idx] != row:
|
3793
|
+
self.MT.displayed_rows.insert(idx, row)
|
3794
|
+
rhs.insert(idx, self.MT.saved_row_heights.pop(row, self.MT.get_default_row_height()))
|
3795
|
+
self.MT.set_row_positions(rhs)
|
3796
|
+
if deselect_all:
|
3797
|
+
self.MT.deselect(redraw=False)
|
3798
|
+
self.set_refresh_timer(redraw)
|
3586
3799
|
return self
|
3587
3800
|
|
3588
3801
|
def all_rows_displayed(self, a: bool | None = None) -> bool:
|
@@ -3734,22 +3947,34 @@ class Sheet(tk.Frame):
|
|
3734
3947
|
def set_text_editor_value(
|
3735
3948
|
self,
|
3736
3949
|
text: str = "",
|
3737
|
-
r: int | None = None,
|
3738
|
-
c: int | None = None,
|
3739
3950
|
) -> Sheet:
|
3740
|
-
if self.MT.text_editor
|
3741
|
-
self.MT.text_editor.set_text(text)
|
3742
|
-
|
3743
|
-
|
3951
|
+
if self.MT.text_editor.open:
|
3952
|
+
self.MT.text_editor.window.set_text(text)
|
3953
|
+
return self
|
3954
|
+
|
3955
|
+
def set_index_text_editor_value(
|
3956
|
+
self,
|
3957
|
+
text: str = "",
|
3958
|
+
) -> Sheet:
|
3959
|
+
if self.RI.text_editor.open:
|
3960
|
+
self.RI.text_editor.window.set_text(text)
|
3961
|
+
return self
|
3962
|
+
|
3963
|
+
def set_header_text_editor_value(
|
3964
|
+
self,
|
3965
|
+
text: str = "",
|
3966
|
+
) -> Sheet:
|
3967
|
+
if self.CH.text_editor.open:
|
3968
|
+
self.CH.text_editor.window.set_text(text)
|
3744
3969
|
return self
|
3745
3970
|
|
3746
3971
|
def destroy_text_editor(self, event: object = None) -> Sheet:
|
3747
|
-
self.MT.
|
3972
|
+
self.MT.hide_text_editor(event=event)
|
3748
3973
|
return self
|
3749
3974
|
|
3750
3975
|
def get_text_editor_widget(self, event: object = None) -> tk.Text | None:
|
3751
3976
|
try:
|
3752
|
-
return self.MT.text_editor.
|
3977
|
+
return self.MT.text_editor.tktext
|
3753
3978
|
except Exception:
|
3754
3979
|
return None
|
3755
3980
|
|
@@ -3761,7 +3986,7 @@ class Sheet(tk.Frame):
|
|
3761
3986
|
if key == "all":
|
3762
3987
|
for key in self.MT.text_editor_user_bound_keys:
|
3763
3988
|
try:
|
3764
|
-
self.MT.text_editor.
|
3989
|
+
self.MT.text_editor.tktext.unbind(key)
|
3765
3990
|
except Exception:
|
3766
3991
|
pass
|
3767
3992
|
self.MT.text_editor_user_bound_keys = {}
|
@@ -3769,19 +3994,18 @@ class Sheet(tk.Frame):
|
|
3769
3994
|
if key in self.MT.text_editor_user_bound_keys:
|
3770
3995
|
del self.MT.text_editor_user_bound_keys[key]
|
3771
3996
|
try:
|
3772
|
-
self.MT.text_editor.
|
3997
|
+
self.MT.text_editor.tktext.unbind(key)
|
3773
3998
|
except Exception:
|
3774
3999
|
pass
|
3775
4000
|
return self
|
3776
4001
|
|
3777
4002
|
def get_text_editor_value(self) -> str | None:
|
3778
|
-
|
3779
|
-
return self.MT.text_editor.get()
|
4003
|
+
return self.MT.text_editor.get()
|
3780
4004
|
|
3781
4005
|
def close_text_editor(self, set_data: bool = True) -> Sheet:
|
3782
|
-
if self.MT.text_editor:
|
4006
|
+
if self.MT.text_editor.open:
|
3783
4007
|
event = ("ButtonPress-1",) if set_data else ("Escape",)
|
3784
|
-
self.MT.close_text_editor(editor_info=self.MT.
|
4008
|
+
self.MT.close_text_editor(editor_info=self.MT.text_editor.coords + event)
|
3785
4009
|
return self
|
3786
4010
|
|
3787
4011
|
# Sheet Options and Other Functions
|
@@ -3841,11 +4065,44 @@ class Sheet(tk.Frame):
|
|
3841
4065
|
highlightbackground=kwargs["outline_color"],
|
3842
4066
|
highlightcolor=kwargs["outline_color"],
|
3843
4067
|
)
|
4068
|
+
if any(k in kwargs for k in scrollbar_options_keys):
|
4069
|
+
self.set_scrollbar_options()
|
3844
4070
|
self.MT.create_rc_menus()
|
3845
4071
|
self.MT.key_bindings()
|
3846
4072
|
self.set_refresh_timer(redraw)
|
3847
4073
|
return self
|
3848
4074
|
|
4075
|
+
def set_scrollbar_options(self) -> Sheet:
|
4076
|
+
style = ttk.Style()
|
4077
|
+
for orientation in ("vertical", "horizontal"):
|
4078
|
+
style.configure(
|
4079
|
+
f"Sheet{self.unique_id}.{orientation.capitalize()}.TScrollbar",
|
4080
|
+
background=self.ops[f"{orientation}_scroll_background"],
|
4081
|
+
troughcolor=self.ops[f"{orientation}_scroll_troughcolor"],
|
4082
|
+
lightcolor=self.ops[f"{orientation}_scroll_lightcolor"],
|
4083
|
+
darkcolor=self.ops[f"{orientation}_scroll_darkcolor"],
|
4084
|
+
relief=self.ops[f"{orientation}_scroll_relief"],
|
4085
|
+
troughrelief=self.ops[f"{orientation}_scroll_troughrelief"],
|
4086
|
+
bordercolor=self.ops[f"{orientation}_scroll_bordercolor"],
|
4087
|
+
borderwidth=self.ops[f"{orientation}_scroll_borderwidth"],
|
4088
|
+
gripcount=self.ops[f"{orientation}_scroll_gripcount"],
|
4089
|
+
arrowsize=self.ops[f"{orientation}_scroll_arrowsize"],
|
4090
|
+
)
|
4091
|
+
style.map(
|
4092
|
+
f"Sheet{self.unique_id}.{orientation.capitalize()}.TScrollbar",
|
4093
|
+
foreground=[
|
4094
|
+
("!active", self.ops[f"{orientation}_scroll_not_active_fg"]),
|
4095
|
+
("pressed", self.ops[f"{orientation}_scroll_pressed_fg"]),
|
4096
|
+
("active", self.ops[f"{orientation}_scroll_active_fg"]),
|
4097
|
+
],
|
4098
|
+
background=[
|
4099
|
+
("!active", self.ops[f"{orientation}_scroll_not_active_bg"]),
|
4100
|
+
("pressed", self.ops[f"{orientation}_scroll_pressed_bg"]),
|
4101
|
+
("active", self.ops[f"{orientation}_scroll_active_bg"]),
|
4102
|
+
],
|
4103
|
+
)
|
4104
|
+
return self
|
4105
|
+
|
3849
4106
|
def get_cell_options(
|
3850
4107
|
self,
|
3851
4108
|
key: None | str = None,
|
@@ -3946,6 +4203,570 @@ class Sheet(tk.Frame):
|
|
3946
4203
|
self.MT.main_table_redraw_grid_and_text(redraw_header=redraw_header, redraw_row_index=redraw_row_index)
|
3947
4204
|
return self
|
3948
4205
|
|
4206
|
+
# Tags
|
4207
|
+
|
4208
|
+
def tag(
|
4209
|
+
self,
|
4210
|
+
*key: CreateSpanTypes,
|
4211
|
+
tags: Iterator[str] | str = "",
|
4212
|
+
) -> Sheet:
|
4213
|
+
span = self.span_from_key(*key)
|
4214
|
+
rows, cols = self.ranges_from_span(span)
|
4215
|
+
if isinstance(tags, str):
|
4216
|
+
tags = (tags,)
|
4217
|
+
if span.kind == "cell":
|
4218
|
+
for tag in tags:
|
4219
|
+
if tag not in self.MT.tagged_cells:
|
4220
|
+
self.MT.tagged_cells[tag] = set()
|
4221
|
+
for r in rows:
|
4222
|
+
for c in cols:
|
4223
|
+
self.MT.tagged_cells[tag].add((r, c))
|
4224
|
+
elif span.kind == "row":
|
4225
|
+
for tag in tags:
|
4226
|
+
if tag not in self.MT.tagged_rows:
|
4227
|
+
self.MT.tagged_rows[tag] = set()
|
4228
|
+
self.MT.tagged_rows[tag].update(set(rows))
|
4229
|
+
elif span.kind == "column":
|
4230
|
+
for tag in tags:
|
4231
|
+
if tag not in self.MT.tagged_columns:
|
4232
|
+
self.MT.tagged_columns[tag] = set()
|
4233
|
+
self.MT.tagged_columns[tag].update(set(cols))
|
4234
|
+
return self
|
4235
|
+
|
4236
|
+
def tag_cell(
|
4237
|
+
self,
|
4238
|
+
cell: tuple[int, int],
|
4239
|
+
*tags,
|
4240
|
+
) -> Sheet:
|
4241
|
+
if (
|
4242
|
+
not isinstance(cell, tuple)
|
4243
|
+
or not len(cell) == 2
|
4244
|
+
or not isinstance(cell[0], int)
|
4245
|
+
or not isinstance(cell[1], int)
|
4246
|
+
):
|
4247
|
+
raise ValueError("'cell' argument must be tuple[int, int].")
|
4248
|
+
for tag in unpack(tags):
|
4249
|
+
if tag not in self.MT.tagged_cells:
|
4250
|
+
self.MT.tagged_cells[tag] = set()
|
4251
|
+
self.MT.tagged_cells[tag].add(cell)
|
4252
|
+
return self
|
4253
|
+
|
4254
|
+
def tag_rows(
|
4255
|
+
self,
|
4256
|
+
rows: int | Iterator[int],
|
4257
|
+
*tags,
|
4258
|
+
) -> Sheet:
|
4259
|
+
if isinstance(rows, int):
|
4260
|
+
rows = [rows]
|
4261
|
+
for tag in unpack(tags):
|
4262
|
+
if tag not in self.MT.tagged_rows:
|
4263
|
+
self.MT.tagged_rows[tag] = set()
|
4264
|
+
self.MT.tagged_rows[tag].update(rows)
|
4265
|
+
return self
|
4266
|
+
|
4267
|
+
def tag_columns(
|
4268
|
+
self,
|
4269
|
+
columns: int | Iterator[int],
|
4270
|
+
*tags,
|
4271
|
+
) -> Sheet:
|
4272
|
+
if isinstance(columns, int):
|
4273
|
+
columns = [columns]
|
4274
|
+
for tag in unpack(tags):
|
4275
|
+
if tag not in self.MT.tagged_columns:
|
4276
|
+
self.MT.tagged_columns[tag] = set()
|
4277
|
+
self.MT.tagged_columns[tag].update(columns)
|
4278
|
+
return self
|
4279
|
+
|
4280
|
+
def untag(
|
4281
|
+
self,
|
4282
|
+
cell: tuple[int, int] | None = None,
|
4283
|
+
rows: int | Iterator[int] | None = None,
|
4284
|
+
columns: int | Iterator[int] | None = None,
|
4285
|
+
) -> Sheet:
|
4286
|
+
if isinstance(cell, tuple):
|
4287
|
+
for tagged in self.MT.tagged_cells.values():
|
4288
|
+
tagged.discard(cell)
|
4289
|
+
if isinstance(rows, int):
|
4290
|
+
rows = (rows,)
|
4291
|
+
if is_iterable(rows):
|
4292
|
+
for tagged in self.MT.tagged_rows.values():
|
4293
|
+
for row in rows:
|
4294
|
+
tagged.discard(row)
|
4295
|
+
if isinstance(columns, int):
|
4296
|
+
columns = (columns,)
|
4297
|
+
if is_iterable(columns):
|
4298
|
+
for tagged in self.MT.tagged_columns.values():
|
4299
|
+
for column in columns:
|
4300
|
+
tagged.discard(column)
|
4301
|
+
return self
|
4302
|
+
|
4303
|
+
def tag_del(
|
4304
|
+
self,
|
4305
|
+
*tags,
|
4306
|
+
cells: bool = True,
|
4307
|
+
rows: bool = True,
|
4308
|
+
columns: bool = True,
|
4309
|
+
) -> Sheet:
|
4310
|
+
for tag in unpack(tags):
|
4311
|
+
if cells and tag in self.MT.tagged_cells:
|
4312
|
+
del self.MT.tagged_cells[tag]
|
4313
|
+
if rows and tag in self.MT.tagged_rows:
|
4314
|
+
del self.MT.tagged_rows[tag]
|
4315
|
+
if columns and tag in self.MT.tagged_columns:
|
4316
|
+
del self.MT.tagged_columns[tag]
|
4317
|
+
return self
|
4318
|
+
|
4319
|
+
def tag_has(
|
4320
|
+
self,
|
4321
|
+
*tags,
|
4322
|
+
) -> DotDict:
|
4323
|
+
res = DotDict(
|
4324
|
+
cells=set(),
|
4325
|
+
rows=set(),
|
4326
|
+
columns=set(),
|
4327
|
+
)
|
4328
|
+
for tag in unpack(tags):
|
4329
|
+
res.cells.update(self.MT.tagged_cells[tag] if tag in self.MT.tagged_cells else set())
|
4330
|
+
res.rows.update(self.MT.tagged_rows[tag] if tag in self.MT.tagged_rows else set())
|
4331
|
+
res.columns.update(self.MT.tagged_columns[tag] if tag in self.MT.tagged_columns else set())
|
4332
|
+
return res
|
4333
|
+
|
4334
|
+
# Treeview Mode
|
4335
|
+
|
4336
|
+
def tree_build(
|
4337
|
+
self,
|
4338
|
+
data: list[list[object]],
|
4339
|
+
iid_column: int,
|
4340
|
+
parent_column: int,
|
4341
|
+
) -> Sheet:
|
4342
|
+
tally_of_ids = defaultdict(lambda: -1)
|
4343
|
+
ncols = max(map(len, data), default=0)
|
4344
|
+
for rn, row in enumerate(data):
|
4345
|
+
if ncols > (lnr := len(row)):
|
4346
|
+
row += self.MT.get_empty_row_seq(rn, end=ncols, start=lnr)
|
4347
|
+
iid, pid = row[iid_column].lower(), row[parent_column].lower()
|
4348
|
+
if not iid:
|
4349
|
+
continue
|
4350
|
+
tally_of_ids[iid] += 1
|
4351
|
+
if tally_of_ids[iid] > 0:
|
4352
|
+
x = 1
|
4353
|
+
while iid in tally_of_ids:
|
4354
|
+
new = f"{row[iid_column]}_DUPLICATED_{x}"
|
4355
|
+
iid = new.lower()
|
4356
|
+
x += 1
|
4357
|
+
tally_of_ids[iid] += 1
|
4358
|
+
row[iid_column] = new
|
4359
|
+
if iid not in self.RI.tree:
|
4360
|
+
self.RI.tree[iid] = Node(row[iid_column], iid, "")
|
4361
|
+
if iid == pid or self.RI.pid_causes_recursive_loop(iid, pid):
|
4362
|
+
row[parent_column] = ""
|
4363
|
+
pid = ""
|
4364
|
+
if pid:
|
4365
|
+
if pid not in self.RI.tree:
|
4366
|
+
self.RI.tree[pid] = Node(row[parent_column], pid)
|
4367
|
+
self.RI.tree[iid].parent = self.RI.tree[pid]
|
4368
|
+
self.RI.tree[pid].children.append(self.RI.tree[iid])
|
4369
|
+
else:
|
4370
|
+
self.RI.tree[iid].parent = ""
|
4371
|
+
self.RI.tree_rns[iid] = rn
|
4372
|
+
for n in self.RI.tree.values():
|
4373
|
+
if n.parent is None:
|
4374
|
+
n.parent = ""
|
4375
|
+
newrow = self.MT.get_empty_row_seq(len(data), ncols)
|
4376
|
+
newrow[iid_column] = n.text
|
4377
|
+
self.RI.tree_rns[n.iid] = len(data)
|
4378
|
+
data.append(newrow)
|
4379
|
+
self.insert_rows(
|
4380
|
+
idx=0,
|
4381
|
+
rows=[[self.RI.tree[iid]] + data[self.RI.tree_rns[iid]] for iid in self.get_children()],
|
4382
|
+
row_index=True,
|
4383
|
+
create_selections=False,
|
4384
|
+
fill=False,
|
4385
|
+
)
|
4386
|
+
self.RI.tree_rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
4387
|
+
self.hide_rows(
|
4388
|
+
set(self.RI.tree_rns[iid] for iid in self.get_children() if self.RI.tree[iid].parent),
|
4389
|
+
deselect_all=True,
|
4390
|
+
data_indexes=True,
|
4391
|
+
)
|
4392
|
+
return self
|
4393
|
+
|
4394
|
+
def insert(
|
4395
|
+
self,
|
4396
|
+
parent: str = "",
|
4397
|
+
index: None | int | Literal["end"] = None,
|
4398
|
+
iid: None | str = None,
|
4399
|
+
text: None | str = None,
|
4400
|
+
values: None | list = None,
|
4401
|
+
create_selections: bool = False,
|
4402
|
+
) -> str:
|
4403
|
+
if iid is None:
|
4404
|
+
i = 0
|
4405
|
+
while (iid := f"{i}") in self.RI.tree:
|
4406
|
+
i += 1
|
4407
|
+
iid, pid = iid.lower(), parent.lower()
|
4408
|
+
if not iid:
|
4409
|
+
raise ValueError("iid cannot be empty string.")
|
4410
|
+
if iid in self.RI.tree:
|
4411
|
+
raise ValueError(f"iid '{iid}' already exists.")
|
4412
|
+
if iid == pid:
|
4413
|
+
raise ValueError(f"iid '{iid}' cannot be equal to parent '{pid}'.")
|
4414
|
+
if pid and pid not in self.RI.tree:
|
4415
|
+
raise ValueError(f"parent '{parent}' does not exist.")
|
4416
|
+
if text is None:
|
4417
|
+
text = iid
|
4418
|
+
parent_node = self.RI.tree[pid] if parent else ""
|
4419
|
+
self.RI.tree[iid] = Node(text, iid, parent_node)
|
4420
|
+
if self.RI.pid_causes_recursive_loop(iid, pid):
|
4421
|
+
del self.RI.tree[iid]
|
4422
|
+
raise ValueError(f"iid '{iid}' causes a recursive loop with parent '{parent}'.")
|
4423
|
+
if parent_node:
|
4424
|
+
if isinstance(index, int):
|
4425
|
+
idx = self.RI.tree_rns[pid] + index + 1
|
4426
|
+
for count, cid in enumerate(self.get_children(pid)):
|
4427
|
+
if count >= index:
|
4428
|
+
break
|
4429
|
+
idx += sum(1 for _ in self.RI.get_iid_descendants(cid))
|
4430
|
+
self.RI.tree[pid].children.insert(index, self.RI.tree[iid])
|
4431
|
+
else:
|
4432
|
+
idx = self.RI.tree_rns[pid] + sum(1 for _ in self.RI.get_iid_descendants(pid)) + 1
|
4433
|
+
self.RI.tree[pid].children.append(self.RI.tree[iid])
|
4434
|
+
else:
|
4435
|
+
if isinstance(index, int):
|
4436
|
+
idx = index
|
4437
|
+
if index:
|
4438
|
+
for count, cid in enumerate(self.get_children("")):
|
4439
|
+
if count >= index:
|
4440
|
+
break
|
4441
|
+
idx += sum(1 for _ in self.RI.get_iid_descendants(cid)) + 1
|
4442
|
+
else:
|
4443
|
+
idx = len(self.MT._row_index)
|
4444
|
+
self.insert_rows(
|
4445
|
+
idx=idx,
|
4446
|
+
rows=[[self.RI.tree[iid]] + [] if values is None else values],
|
4447
|
+
row_index=True,
|
4448
|
+
create_selections=create_selections,
|
4449
|
+
fill=False,
|
4450
|
+
)
|
4451
|
+
self.RI.tree_rns[iid] = idx
|
4452
|
+
if pid and (pid not in self.RI.tree_open_ids or not self.item_displayed(pid)):
|
4453
|
+
self.hide_rows(idx, deselect_all=False, data_indexes=True)
|
4454
|
+
return iid
|
4455
|
+
|
4456
|
+
def item(
|
4457
|
+
self,
|
4458
|
+
item: str,
|
4459
|
+
iid: str | None = None,
|
4460
|
+
text: str | None = None,
|
4461
|
+
values: list | None = None,
|
4462
|
+
open_: bool | None = None,
|
4463
|
+
) -> DotDict:
|
4464
|
+
if not (item := item.lower()) or item not in self.RI.tree:
|
4465
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4466
|
+
if isinstance(iid, str):
|
4467
|
+
if not (iid := iid.lower()):
|
4468
|
+
raise ValueError(f"iid '{iid}' does not exist.")
|
4469
|
+
if iid in self.RI.tree:
|
4470
|
+
raise ValueError(f"Cannot rename '{iid}', it already exists.")
|
4471
|
+
iid = iid.lower()
|
4472
|
+
self.RI.tree[item].iid = iid
|
4473
|
+
self.RI.tree[iid] = self.RI.tree.pop(item)
|
4474
|
+
self.RI.tree_rns[iid] = self.RI.tree_rns.pop(item)
|
4475
|
+
if iid in self.RI.tree_open_ids:
|
4476
|
+
self.RI.tree_open_ids[iid] = self.RI.tree_open_ids.pop(item)
|
4477
|
+
if isinstance(text, str):
|
4478
|
+
self.RI.tree[item].text = text
|
4479
|
+
if isinstance(values, list):
|
4480
|
+
self.set_data(self.RI.tree_rns[item], values)
|
4481
|
+
if isinstance(open_, bool):
|
4482
|
+
if not self.RI.tree[item].children or not open_:
|
4483
|
+
self.RI.tree_open_ids.discard(item)
|
4484
|
+
if open_:
|
4485
|
+
self.RI.tree_open_ids.add(item)
|
4486
|
+
self.show_rows(
|
4487
|
+
(self.RI.tree_rns[did] for did in self.RI.get_iid_descendants(item, check_open=True)),
|
4488
|
+
redraw=False,
|
4489
|
+
deselect_all=False,
|
4490
|
+
)
|
4491
|
+
elif self.RI.tree[item].children:
|
4492
|
+
self.hide_rows(
|
4493
|
+
(self.RI.tree_rns[did] for did in self.RI.get_iid_descendants(item)),
|
4494
|
+
redraw=False,
|
4495
|
+
deselect_all=False,
|
4496
|
+
data_indexes=True,
|
4497
|
+
)
|
4498
|
+
self.set_refresh_timer(isinstance(text, str) or isinstance(values, list) or isinstance(open_, bool))
|
4499
|
+
return DotDict(
|
4500
|
+
text=self.RI.tree[item].text,
|
4501
|
+
values=self[self.RI.tree_rns[item]].options(ndim=1).data,
|
4502
|
+
open_=item in self.RI.tree_open_ids,
|
4503
|
+
)
|
4504
|
+
|
4505
|
+
def itemrow(self, item: str) -> int:
|
4506
|
+
return self.RI.tree_rns[item.lower()]
|
4507
|
+
|
4508
|
+
def rowitem(self, row: int) -> str | None:
|
4509
|
+
if len(self.MT._row_index) > row:
|
4510
|
+
return self.MT._row_index[row].iid
|
4511
|
+
return None
|
4512
|
+
|
4513
|
+
def get_children(self, item: None | str = None) -> Generator[str]:
|
4514
|
+
if item is None:
|
4515
|
+
for n in self.RI.tree.values():
|
4516
|
+
if not n.parent:
|
4517
|
+
yield n.iid
|
4518
|
+
for iid in self.RI.get_iid_descendants(n.iid):
|
4519
|
+
yield iid
|
4520
|
+
elif item == "":
|
4521
|
+
yield from (n.iid for n in self.RI.tree.values() if not n.parent)
|
4522
|
+
else:
|
4523
|
+
yield from (n.iid for n in self.RI.tree[item].children)
|
4524
|
+
|
4525
|
+
def reset_tree(self) -> Sheet:
|
4526
|
+
self.deselect()
|
4527
|
+
self.RI.reset_tree()
|
4528
|
+
return self
|
4529
|
+
|
4530
|
+
def del_items(self, *items) -> Sheet:
|
4531
|
+
"""
|
4532
|
+
Also deletes all descendants of items
|
4533
|
+
"""
|
4534
|
+
rows_to_del = []
|
4535
|
+
iids_to_del = []
|
4536
|
+
for item in unpack(items):
|
4537
|
+
item = item.lower()
|
4538
|
+
if item not in self.RI.tree:
|
4539
|
+
continue
|
4540
|
+
rows_to_del.append(self.RI.tree_rns[item])
|
4541
|
+
iids_to_del.append(item)
|
4542
|
+
for did in self.RI.get_iid_descendants(item):
|
4543
|
+
rows_to_del.append(self.RI.tree_rns[did])
|
4544
|
+
iids_to_del.append(did)
|
4545
|
+
for item in unpack(items):
|
4546
|
+
self.RI.remove_node_from_parents_children(self.RI.tree[item])
|
4547
|
+
self.del_rows(rows_to_del)
|
4548
|
+
for iid in iids_to_del:
|
4549
|
+
self.RI.tree_open_ids.discard(iid)
|
4550
|
+
if self.RI.tree[iid].parent and len(self.RI.tree[iid].parent.children) == 1:
|
4551
|
+
self.RI.tree_open_ids.discard(self.RI.tree[iid].parent.iid)
|
4552
|
+
del self.RI.tree[iid]
|
4553
|
+
self.set_refresh_timer(True)
|
4554
|
+
return self
|
4555
|
+
|
4556
|
+
def set_children(self, item: str, *newchildren) -> Sheet:
|
4557
|
+
"""
|
4558
|
+
Moves everything in '*newchildren' under 'item'
|
4559
|
+
"""
|
4560
|
+
if (item := item.lower()) and item not in self.RI.tree:
|
4561
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4562
|
+
mapping = {}
|
4563
|
+
to_show = []
|
4564
|
+
if item:
|
4565
|
+
new_parent = self.RI.tree[item]
|
4566
|
+
if new_parent.children:
|
4567
|
+
ctr = self.RI.tree_rns[new_parent.children[-1].iid] + 1
|
4568
|
+
else:
|
4569
|
+
ctr = self.RI.tree_rns[new_parent.iid] + 1
|
4570
|
+
for cid in unpack(newchildren):
|
4571
|
+
if self.RI.pid_causes_recursive_loop(cid, item):
|
4572
|
+
raise ValueError(f"iid '{cid}' causes a recursive loop with parent '{item}'.")
|
4573
|
+
cid_node = self.RI.tree[cid]
|
4574
|
+
mapping[self.RI.tree_rns[cid]] = ctr
|
4575
|
+
if item in self.RI.tree_open_ids and self.item_displayed(item):
|
4576
|
+
to_show.append(ctr)
|
4577
|
+
ctr += 1
|
4578
|
+
for did in self.RI.get_iid_descendants(cid):
|
4579
|
+
mapping[self.RI.tree_rns[did]] = ctr
|
4580
|
+
if to_show and self.RI.ancestors_all_open(did, self.RI.tree[cid].parent):
|
4581
|
+
to_show.append(ctr)
|
4582
|
+
ctr += 1
|
4583
|
+
self.RI.remove_node_from_parents_children(cid_node)
|
4584
|
+
cid_node.parent = new_parent
|
4585
|
+
new_parent.children.append(cid_node)
|
4586
|
+
else:
|
4587
|
+
ctr = (
|
4588
|
+
len(self.MT._row_index)
|
4589
|
+
- len(newchildren)
|
4590
|
+
- sum(1 for cid in unpack(newchildren) for _ in self.RI.get_iid_descendants(cid))
|
4591
|
+
)
|
4592
|
+
for cid in unpack(newchildren):
|
4593
|
+
cid_node = self.RI.tree[cid]
|
4594
|
+
mapping[self.RI.tree_rns[cid]] = ctr
|
4595
|
+
to_show.append(ctr)
|
4596
|
+
ctr += 1
|
4597
|
+
for did in self.RI.get_iid_descendants(cid):
|
4598
|
+
mapping[self.RI.tree_rns[did]] = ctr
|
4599
|
+
if self.RI.ancestors_all_open(did, cid_node.parent):
|
4600
|
+
to_show.append(ctr)
|
4601
|
+
ctr += 1
|
4602
|
+
self.RI.remove_node_from_parents_children(cid_node)
|
4603
|
+
self.RI.tree[cid].parent = ""
|
4604
|
+
self.mapping_move_rows(
|
4605
|
+
data_new_idxs=mapping,
|
4606
|
+
data_indexes=True,
|
4607
|
+
create_selections=False,
|
4608
|
+
redraw=False,
|
4609
|
+
)
|
4610
|
+
if item and (item not in self.RI.tree_open_ids or not self.item_displayed(item)):
|
4611
|
+
self.hide_rows(set(mapping.values()), data_indexes=True)
|
4612
|
+
self.show_rows(to_show)
|
4613
|
+
self.set_refresh_timer(True)
|
4614
|
+
return self
|
4615
|
+
|
4616
|
+
def move(self, item: str, parent: str, index: int = 0) -> Sheet:
|
4617
|
+
"""
|
4618
|
+
Moves item to be under parent as child at index
|
4619
|
+
'parent' can be empty string which will make item a top node
|
4620
|
+
"""
|
4621
|
+
if (item := item.lower()) and item not in self.RI.tree:
|
4622
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4623
|
+
if (parent := parent.lower()) and parent not in self.RI.tree:
|
4624
|
+
raise ValueError(f"Parent '{parent}' does not exist.")
|
4625
|
+
mapping = {}
|
4626
|
+
to_show = []
|
4627
|
+
item_node = self.RI.tree[item]
|
4628
|
+
if parent:
|
4629
|
+
if self.RI.pid_causes_recursive_loop(item, parent):
|
4630
|
+
raise ValueError(f"iid '{item}' causes a recursive loop with parent '{parent}'.")
|
4631
|
+
parent_node = self.RI.tree[parent]
|
4632
|
+
if parent_node.children:
|
4633
|
+
if len(parent_node.children) < index:
|
4634
|
+
index = len(parent_node.children)
|
4635
|
+
ctr = self.RI.tree_rns[parent_node.children[index].iid]
|
4636
|
+
else:
|
4637
|
+
ctr = self.RI.tree_rns[parent_node.iid] + 1
|
4638
|
+
mapping[self.RI.tree_rns[item]] = ctr
|
4639
|
+
if parent in self.RI.tree_open_ids and self.item_displayed(parent):
|
4640
|
+
to_show.append(ctr)
|
4641
|
+
ctr += 1
|
4642
|
+
for did in self.RI.get_iid_descendants(item):
|
4643
|
+
mapping[self.RI.tree_rns[did]] = ctr
|
4644
|
+
if to_show and self.RI.ancestors_all_open(did, item_node.parent):
|
4645
|
+
to_show.append(ctr)
|
4646
|
+
ctr += 1
|
4647
|
+
self.RI.remove_node_from_parents_children(item_node)
|
4648
|
+
item_node.parent = parent_node
|
4649
|
+
parent_node.children.append(item_node)
|
4650
|
+
else:
|
4651
|
+
if len(self.MT._row_index) < index:
|
4652
|
+
index = len(self.MT._row_index)
|
4653
|
+
ctr = index
|
4654
|
+
mapping[self.RI.tree_rns[item]] = ctr
|
4655
|
+
to_show.append(ctr)
|
4656
|
+
ctr += 1
|
4657
|
+
for did in self.RI.get_iid_descendants(item):
|
4658
|
+
mapping[self.RI.tree_rns[did]] = ctr
|
4659
|
+
if to_show and self.RI.ancestors_all_open(did, item_node.parent):
|
4660
|
+
to_show.append(ctr)
|
4661
|
+
ctr += 1
|
4662
|
+
self.RI.remove_node_from_parents_children(item_node)
|
4663
|
+
self.RI.tree[item].parent = ""
|
4664
|
+
self.mapping_move_rows(
|
4665
|
+
data_new_idxs=mapping,
|
4666
|
+
data_indexes=True,
|
4667
|
+
create_selections=False,
|
4668
|
+
redraw=False,
|
4669
|
+
)
|
4670
|
+
if parent and (parent not in self.RI.tree_open_ids or not self.item_displayed(parent)):
|
4671
|
+
self.hide_rows(set(mapping.values()), data_indexes=True)
|
4672
|
+
self.show_rows(to_show)
|
4673
|
+
self.set_refresh_timer(True)
|
4674
|
+
return self
|
4675
|
+
|
4676
|
+
reattach = move
|
4677
|
+
|
4678
|
+
def exists(self, item: str) -> bool:
|
4679
|
+
return item in self.RI.tree
|
4680
|
+
|
4681
|
+
def parent(self, item: str) -> str:
|
4682
|
+
if (item := item.lower()) not in self.RI.tree:
|
4683
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4684
|
+
return self.RI.tree[item].parent.iid if self.RI.tree[item].parent else self.RI.tree[item].parent
|
4685
|
+
|
4686
|
+
def index(self, item: str) -> int:
|
4687
|
+
if (item := item.lower()) not in self.RI.tree:
|
4688
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4689
|
+
if not self.RI.tree[item].parent:
|
4690
|
+
return sorted(self.RI.tree_rns[iid] for iid in self.get_children("")).index(self.RI.tree_rns[item])
|
4691
|
+
return self.RI.tree[item].parent.children.index(self.RI.tree[item])
|
4692
|
+
|
4693
|
+
def item_displayed(self, item: str) -> bool:
|
4694
|
+
"""
|
4695
|
+
Check if an item (row) is currently displayed on the sheet
|
4696
|
+
- Does not check if the item is visible to the user
|
4697
|
+
"""
|
4698
|
+
if (item := item.lower()) not in self.RI.tree:
|
4699
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4700
|
+
return self.RI.tree_rns[item] in self.MT.displayed_rows
|
4701
|
+
|
4702
|
+
def display_item(self, item: str) -> Sheet:
|
4703
|
+
"""
|
4704
|
+
Ensure that item is displayed in the tree
|
4705
|
+
- Opens all of an item's ancestors
|
4706
|
+
- Unlike the ttk treeview 'see' function
|
4707
|
+
this function does **NOT** scroll to the item
|
4708
|
+
"""
|
4709
|
+
if (item := item.lower()) not in self.RI.tree:
|
4710
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4711
|
+
if self.RI.tree[item].parent:
|
4712
|
+
for iid in self.RI.get_iid_ancestors(item):
|
4713
|
+
self.item(iid, open_=True)
|
4714
|
+
|
4715
|
+
def scroll_to_item(self, item: str) -> Sheet:
|
4716
|
+
"""
|
4717
|
+
Scrolls to an item and ensures that it is displayed
|
4718
|
+
"""
|
4719
|
+
if (item := item.lower()) not in self.RI.tree:
|
4720
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4721
|
+
self.display_item(item)
|
4722
|
+
self.see(row=bisect_left(self.MT.displayed_rows, self.RI.tree_rns[item]), keep_xscroll=True)
|
4723
|
+
|
4724
|
+
def selection(self) -> list[str]:
|
4725
|
+
"""
|
4726
|
+
Get currently selected item ids
|
4727
|
+
- Only includes selected rows
|
4728
|
+
"""
|
4729
|
+
return [self.MT._row_index[self.displayed_row_to_data(rn)].iid for rn in self.get_selected_rows()]
|
4730
|
+
|
4731
|
+
def selection_set(self, *items) -> Sheet:
|
4732
|
+
self.deselect()
|
4733
|
+
self.selection_add(*items)
|
4734
|
+
return self
|
4735
|
+
|
4736
|
+
def selection_add(self, *items) -> Sheet:
|
4737
|
+
for item in unpack(items):
|
4738
|
+
if (item := item.lower()) not in self.RI.tree:
|
4739
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4740
|
+
if not self.item_displayed(item):
|
4741
|
+
self.display_item(item)
|
4742
|
+
self.add_row_selection(bisect_left(self.MT.displayed_rows, self.RI.tree_rns[item]))
|
4743
|
+
return self
|
4744
|
+
|
4745
|
+
def selection_remove(self, *items) -> Sheet:
|
4746
|
+
for item in unpack(items):
|
4747
|
+
if (item := item.lower()) not in self.RI.tree:
|
4748
|
+
raise ValueError(f"Item '{item}' does not exist.")
|
4749
|
+
try:
|
4750
|
+
self.deselect(bisect_left(self.MT.displayed_rows, self.RI.tree_rns[item]))
|
4751
|
+
except Exception:
|
4752
|
+
continue
|
4753
|
+
return self
|
4754
|
+
|
4755
|
+
def selection_toggle(self, *items) -> Sheet:
|
4756
|
+
selected = set(self.MT._row_index[self.displayed_row_to_data(rn)].iid for rn in self.get_selected_rows())
|
4757
|
+
add = []
|
4758
|
+
remove = []
|
4759
|
+
for item in unpack(items):
|
4760
|
+
if (item := item.lower()) not in self.RI.tree:
|
4761
|
+
continue
|
4762
|
+
if item in selected:
|
4763
|
+
remove.append(item)
|
4764
|
+
else:
|
4765
|
+
add.append(item)
|
4766
|
+
self.selection_remove(*remove)
|
4767
|
+
self.selection_add(*add)
|
4768
|
+
return self
|
4769
|
+
|
3949
4770
|
# Functions not in docs
|
3950
4771
|
|
3951
4772
|
def emit_event(
|
@@ -3983,10 +4804,10 @@ class Sheet(tk.Frame):
|
|
3983
4804
|
table, index, header = span.table, span.index, span.header
|
3984
4805
|
# index header
|
3985
4806
|
if header and span.kind in ("cell", "column"):
|
3986
|
-
self.CH.
|
4807
|
+
self.CH.hide_dropdown_window()
|
3987
4808
|
del_from_options(self.CH.cell_options, key, cols)
|
3988
4809
|
if index and span.kind in ("cell", "row"):
|
3989
|
-
self.RI.
|
4810
|
+
self.RI.hide_dropdown_window()
|
3990
4811
|
del_from_options(self.RI.cell_options, key, rows)
|
3991
4812
|
# table
|
3992
4813
|
if table and span.kind == "cell":
|
@@ -4001,7 +4822,7 @@ class Sheet(tk.Frame):
|
|
4001
4822
|
# ########## TABLE ##########
|
4002
4823
|
|
4003
4824
|
def del_cell_options_dropdown(self, datarn: int, datacn: int) -> None:
|
4004
|
-
self.MT.
|
4825
|
+
self.MT.hide_dropdown_window()
|
4005
4826
|
if (datarn, datacn) in self.MT.cell_options and "dropdown" in self.MT.cell_options[(datarn, datacn)]:
|
4006
4827
|
del self.MT.cell_options[(datarn, datacn)]["dropdown"]
|
4007
4828
|
|
@@ -4014,7 +4835,7 @@ class Sheet(tk.Frame):
|
|
4014
4835
|
self.del_cell_options_checkbox(datarn, datacn)
|
4015
4836
|
|
4016
4837
|
def del_row_options_dropdown(self, datarn: int) -> None:
|
4017
|
-
self.MT.
|
4838
|
+
self.MT.hide_dropdown_window()
|
4018
4839
|
if datarn in self.MT.row_options and "dropdown" in self.MT.row_options[datarn]:
|
4019
4840
|
del self.MT.row_options[datarn]["dropdown"]
|
4020
4841
|
|
@@ -4027,7 +4848,7 @@ class Sheet(tk.Frame):
|
|
4027
4848
|
self.del_row_options_checkbox(datarn)
|
4028
4849
|
|
4029
4850
|
def del_column_options_dropdown(self, datacn: int) -> None:
|
4030
|
-
self.MT.
|
4851
|
+
self.MT.hide_dropdown_window()
|
4031
4852
|
if datacn in self.MT.col_options and "dropdown" in self.MT.col_options[datacn]:
|
4032
4853
|
del self.MT.col_options[datacn]["dropdown"]
|
4033
4854
|
|
@@ -4042,7 +4863,7 @@ class Sheet(tk.Frame):
|
|
4042
4863
|
# ########## INDEX ##########
|
4043
4864
|
|
4044
4865
|
def del_index_cell_options_dropdown(self, datarn: int) -> None:
|
4045
|
-
self.RI.
|
4866
|
+
self.RI.hide_dropdown_window()
|
4046
4867
|
if datarn in self.RI.cell_options and "dropdown" in self.RI.cell_options[datarn]:
|
4047
4868
|
del self.RI.cell_options[datarn]["dropdown"]
|
4048
4869
|
|
@@ -4057,7 +4878,7 @@ class Sheet(tk.Frame):
|
|
4057
4878
|
# ########## HEADER ##########
|
4058
4879
|
|
4059
4880
|
def del_header_cell_options_dropdown(self, datacn: int) -> None:
|
4060
|
-
self.CH.
|
4881
|
+
self.CH.hide_dropdown_window()
|
4061
4882
|
if datacn in self.CH.cell_options and "dropdown" in self.CH.cell_options[datacn]:
|
4062
4883
|
del self.CH.cell_options[datacn]["dropdown"]
|
4063
4884
|
|
@@ -4390,13 +5211,11 @@ class Sheet(tk.Frame):
|
|
4390
5211
|
|
4391
5212
|
def dehighlight_rows(
|
4392
5213
|
self,
|
4393
|
-
rows: list |
|
5214
|
+
rows: list[int] | Literal["all"] = [],
|
4394
5215
|
redraw: bool = True,
|
4395
5216
|
) -> None:
|
4396
5217
|
if isinstance(rows, int):
|
4397
5218
|
rows = [rows]
|
4398
|
-
else:
|
4399
|
-
rows = rows
|
4400
5219
|
if not rows or rows == "all":
|
4401
5220
|
for r in self.MT.row_options:
|
4402
5221
|
if "highlight" in self.MT.row_options[r]:
|
@@ -4417,11 +5236,13 @@ class Sheet(tk.Frame):
|
|
4417
5236
|
pass
|
4418
5237
|
self.set_refresh_timer(redraw)
|
4419
5238
|
|
4420
|
-
def dehighlight_columns(
|
5239
|
+
def dehighlight_columns(
|
5240
|
+
self,
|
5241
|
+
columns: list[int] | Literal["all"] = [],
|
5242
|
+
redraw: bool = True,
|
5243
|
+
) -> None:
|
4421
5244
|
if isinstance(columns, int):
|
4422
5245
|
columns = [columns]
|
4423
|
-
else:
|
4424
|
-
columns = columns
|
4425
5246
|
if not columns or columns == "all":
|
4426
5247
|
for c in self.MT.col_options:
|
4427
5248
|
if "highlight" in self.MT.col_options[c]:
|
@@ -4444,7 +5265,7 @@ class Sheet(tk.Frame):
|
|
4444
5265
|
|
4445
5266
|
def highlight_rows(
|
4446
5267
|
self,
|
4447
|
-
rows:
|
5268
|
+
rows: Iterator[int] | int,
|
4448
5269
|
bg: None | str = None,
|
4449
5270
|
fg: None | str = None,
|
4450
5271
|
highlight_index: bool = True,
|
@@ -4462,7 +5283,7 @@ class Sheet(tk.Frame):
|
|
4462
5283
|
|
4463
5284
|
def highlight_columns(
|
4464
5285
|
self,
|
4465
|
-
columns:
|
5286
|
+
columns: Iterator[int] | int,
|
4466
5287
|
bg: bool | None | str = False,
|
4467
5288
|
fg: bool | None | str = False,
|
4468
5289
|
highlight_header: bool = True,
|
@@ -4924,26 +5745,17 @@ class Sheet(tk.Frame):
|
|
4924
5745
|
return self
|
4925
5746
|
|
4926
5747
|
def get_checkboxes(self) -> dict:
|
4927
|
-
|
5748
|
+
return {
|
4928
5749
|
**{k: v["checkbox"] for k, v in self.MT.cell_options.items() if "checkbox" in v},
|
4929
5750
|
**{k: v["checkbox"] for k, v in self.MT.row_options.items() if "checkbox" in v},
|
4930
5751
|
**{k: v["checkbox"] for k, v in self.MT.col_options.items() if "checkbox" in v},
|
4931
5752
|
}
|
4932
|
-
if "checkbox" in self.MT.options:
|
4933
|
-
return {**d, "checkbox": self.MT.options["checkbox"]}
|
4934
|
-
return d
|
4935
5753
|
|
4936
5754
|
def get_header_checkboxes(self) -> dict:
|
4937
|
-
|
4938
|
-
if "checkbox" in self.CH.options:
|
4939
|
-
return {**d, "checkbox": self.CH.options["checkbox"]}
|
4940
|
-
return d
|
5755
|
+
return {k: v["checkbox"] for k, v in self.CH.cell_options.items() if "checkbox" in v}
|
4941
5756
|
|
4942
5757
|
def get_index_checkboxes(self) -> dict:
|
4943
|
-
|
4944
|
-
if "checkbox" in self.RI.options:
|
4945
|
-
return {**d, "checkbox": self.RI.options["checkbox"]}
|
4946
|
-
return d
|
5758
|
+
return {k: v["checkbox"] for k, v in self.RI.cell_options.items() if "checkbox" in v}
|
4947
5759
|
|
4948
5760
|
def create_dropdown(
|
4949
5761
|
self,
|
@@ -5190,9 +6002,8 @@ class Sheet(tk.Frame):
|
|
5190
6002
|
set_value: object = None,
|
5191
6003
|
) -> Sheet:
|
5192
6004
|
if set_existing_dropdown:
|
5193
|
-
if self.MT.
|
5194
|
-
r_ = self.MT.
|
5195
|
-
c_ = self.MT.existing_dropdown_window.c
|
6005
|
+
if self.MT.dropdown.open:
|
6006
|
+
r_, c_ = self.MT.dropdown.get_coords()
|
5196
6007
|
else:
|
5197
6008
|
raise Exception("No dropdown box is currently open")
|
5198
6009
|
else:
|
@@ -5200,16 +6011,12 @@ class Sheet(tk.Frame):
|
|
5200
6011
|
c_ = c
|
5201
6012
|
kwargs = self.MT.get_cell_kwargs(r, c, key="dropdown")
|
5202
6013
|
kwargs["values"] = values
|
5203
|
-
if
|
5204
|
-
|
6014
|
+
if self.MT.dropdown.open:
|
6015
|
+
self.MT.dropdown.window.values(values)
|
5205
6016
|
if set_value is not None:
|
5206
6017
|
self.set_cell_data(r_, c_, set_value)
|
5207
|
-
if
|
5208
|
-
|
5209
|
-
and self.MT.text_editor_loc is not None
|
5210
|
-
and self.MT.text_editor is not None
|
5211
|
-
):
|
5212
|
-
self.MT.text_editor.set_text(set_value)
|
6018
|
+
if self.MT.dropdown.open:
|
6019
|
+
self.MT.text_editor.window.set_text(set_value)
|
5213
6020
|
return self
|
5214
6021
|
|
5215
6022
|
def set_header_dropdown_values(
|
@@ -5220,8 +6027,8 @@ class Sheet(tk.Frame):
|
|
5220
6027
|
set_value: object = None,
|
5221
6028
|
) -> Sheet:
|
5222
6029
|
if set_existing_dropdown:
|
5223
|
-
if self.CH.
|
5224
|
-
c_ = self.CH.
|
6030
|
+
if self.CH.dropdown.open:
|
6031
|
+
c_ = self.CH.dropdown.get_coords()
|
5225
6032
|
else:
|
5226
6033
|
raise Exception("No dropdown box is currently open")
|
5227
6034
|
else:
|
@@ -5229,10 +6036,11 @@ class Sheet(tk.Frame):
|
|
5229
6036
|
kwargs = self.CH.get_cell_kwargs(c_, key="dropdown")
|
5230
6037
|
if kwargs:
|
5231
6038
|
kwargs["values"] = values
|
5232
|
-
if
|
5233
|
-
|
6039
|
+
if self.CH.dropdown.open:
|
6040
|
+
self.CH.dropdown.window.values(values)
|
5234
6041
|
if set_value is not None:
|
5235
6042
|
self.MT.headers(newheaders=set_value, index=c_)
|
6043
|
+
|
5236
6044
|
return self
|
5237
6045
|
|
5238
6046
|
def set_index_dropdown_values(
|
@@ -5243,8 +6051,8 @@ class Sheet(tk.Frame):
|
|
5243
6051
|
set_value: object = None,
|
5244
6052
|
) -> Sheet:
|
5245
6053
|
if set_existing_dropdown:
|
5246
|
-
if self.RI.
|
5247
|
-
r_ = self.RI.
|
6054
|
+
if self.RI.current_dropdown_window is not None:
|
6055
|
+
r_ = self.RI.current_dropdown_window.r
|
5248
6056
|
else:
|
5249
6057
|
raise Exception("No dropdown box is currently open")
|
5250
6058
|
else:
|
@@ -5252,10 +6060,11 @@ class Sheet(tk.Frame):
|
|
5252
6060
|
kwargs = self.RI.get_cell_kwargs(r_, key="dropdown")
|
5253
6061
|
if kwargs:
|
5254
6062
|
kwargs["values"] = values
|
5255
|
-
if
|
5256
|
-
|
6063
|
+
if self.RI.current_dropdown_window is not None:
|
6064
|
+
self.RI.current_dropdown_window.values(values)
|
5257
6065
|
if set_value is not None:
|
5258
6066
|
self.MT.row_index(newindex=set_value, index=r_)
|
6067
|
+
# here
|
5259
6068
|
return self
|
5260
6069
|
|
5261
6070
|
def get_dropdown_values(self, r: int = 0, c: int = 0) -> None | list:
|
@@ -5469,7 +6278,7 @@ class Dropdown(Sheet):
|
|
5469
6278
|
parent: tk.Misc,
|
5470
6279
|
r: int,
|
5471
6280
|
c: int,
|
5472
|
-
|
6281
|
+
ops: dict,
|
5473
6282
|
outline_color: str,
|
5474
6283
|
width: int | None = None,
|
5475
6284
|
height: int | None = None,
|
@@ -5481,7 +6290,9 @@ class Dropdown(Sheet):
|
|
5481
6290
|
arrowkey_RIGHT: Callable | None = None,
|
5482
6291
|
arrowkey_LEFT: Callable | None = None,
|
5483
6292
|
align: str = "w",
|
5484
|
-
# False for using r, c
|
6293
|
+
# False for using r, c
|
6294
|
+
# "r" for r
|
6295
|
+
# "c" for c
|
5485
6296
|
single_index: str | bool = False,
|
5486
6297
|
) -> None:
|
5487
6298
|
Sheet.__init__(
|
@@ -5489,7 +6300,7 @@ class Dropdown(Sheet):
|
|
5489
6300
|
parent=parent,
|
5490
6301
|
outline_thickness=outline_thickness,
|
5491
6302
|
outline_color=outline_color,
|
5492
|
-
table_grid_fg=
|
6303
|
+
table_grid_fg=ops.popup_menu_fg,
|
5493
6304
|
show_horizontal_grid=True,
|
5494
6305
|
show_vertical_grid=False,
|
5495
6306
|
show_header=False,
|
@@ -5503,24 +6314,23 @@ class Dropdown(Sheet):
|
|
5503
6314
|
horizontal_grid_to_end_of_window=True,
|
5504
6315
|
set_cell_sizes_on_zoom=True,
|
5505
6316
|
show_selected_cells_border=False,
|
5506
|
-
table_selected_cells_border_fg=
|
5507
|
-
table_selected_cells_bg=
|
5508
|
-
table_selected_rows_border_fg=
|
5509
|
-
table_selected_rows_bg=
|
5510
|
-
table_selected_rows_fg=
|
6317
|
+
table_selected_cells_border_fg=ops.popup_menu_fg,
|
6318
|
+
table_selected_cells_bg=ops.popup_menu_highlight_bg,
|
6319
|
+
table_selected_rows_border_fg=ops.popup_menu_fg,
|
6320
|
+
table_selected_rows_bg=ops.popup_menu_highlight_bg,
|
6321
|
+
table_selected_rows_fg=ops.popup_menu_highlight_fg,
|
5511
6322
|
width=width,
|
5512
6323
|
height=height,
|
5513
6324
|
font=font if font else self.ops.table_font,
|
5514
|
-
table_fg=
|
5515
|
-
table_bg=
|
6325
|
+
table_fg=ops.popup_menu_fg,
|
6326
|
+
table_bg=ops.popup_menu_bg,
|
6327
|
+
**{k: ops[k] for k in scrollbar_options_keys},
|
5516
6328
|
)
|
5517
6329
|
self.parent = parent
|
5518
6330
|
self.close_dropdown_window = close_dropdown_window
|
5519
6331
|
self.search_function = search_function
|
5520
6332
|
self.arrowkey_RIGHT = arrowkey_RIGHT
|
5521
6333
|
self.arrowkey_LEFT = arrowkey_LEFT
|
5522
|
-
self.h_ = height
|
5523
|
-
self.w_ = width
|
5524
6334
|
self.r = r
|
5525
6335
|
self.c = c
|
5526
6336
|
self.row = -1
|
@@ -5599,6 +6409,13 @@ class Dropdown(Sheet):
|
|
5599
6409
|
else:
|
5600
6410
|
self.close_dropdown_window(self.r, self.c, self.get_cell_data(row, 0))
|
5601
6411
|
|
6412
|
+
def get_coords(self) -> int | tuple[int, int]:
|
6413
|
+
if self.single_index == "r":
|
6414
|
+
return self.r
|
6415
|
+
elif self.single_index == "c":
|
6416
|
+
return self.c
|
6417
|
+
return self.r, self.c
|
6418
|
+
|
5602
6419
|
def values(self, values: list = [], redraw: bool = True) -> None:
|
5603
6420
|
self.set_sheet_data(
|
5604
6421
|
[[v] for v in values],
|