tksheet 7.3.3__py3-none-any.whl → 7.4.0__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/colors.py +1 -1
- tksheet/column_headers.py +397 -366
- tksheet/constants.py +13 -0
- tksheet/find_window.py +4 -13
- tksheet/functions.py +198 -37
- tksheet/main_table.py +1109 -848
- tksheet/other_classes.py +13 -9
- tksheet/row_index.py +939 -437
- tksheet/sheet.py +470 -619
- tksheet/sheet_options.py +47 -12
- tksheet/sorting.py +369 -0
- tksheet/text_editor.py +4 -15
- tksheet/{types.py → tksheet_types.py} +12 -8
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/METADATA +14 -14
- tksheet-7.4.0.dist-info/RECORD +22 -0
- tksheet-7.3.3.dist-info/RECORD +0 -21
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/WHEEL +0 -0
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/top_level.txt +0 -0
tksheet/row_index.py
CHANGED
@@ -2,83 +2,61 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import tkinter as tk
|
4
4
|
from collections import defaultdict
|
5
|
-
from collections.abc import
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
from functools import (
|
11
|
-
partial,
|
12
|
-
)
|
13
|
-
from itertools import (
|
14
|
-
chain,
|
15
|
-
cycle,
|
16
|
-
islice,
|
17
|
-
repeat,
|
18
|
-
)
|
19
|
-
from math import (
|
20
|
-
ceil,
|
21
|
-
floor,
|
22
|
-
)
|
23
|
-
from operator import (
|
24
|
-
itemgetter,
|
25
|
-
)
|
5
|
+
from collections.abc import Callable, Generator, Hashable, Sequence
|
6
|
+
from functools import partial
|
7
|
+
from itertools import chain, cycle, islice, repeat
|
8
|
+
from math import ceil, floor
|
9
|
+
from operator import itemgetter
|
26
10
|
from typing import Literal
|
27
11
|
|
28
|
-
from .colors import
|
29
|
-
color_map,
|
30
|
-
)
|
12
|
+
from .colors import color_map
|
31
13
|
from .constants import (
|
14
|
+
_test_str,
|
32
15
|
rc_binding,
|
33
16
|
text_editor_close_bindings,
|
34
17
|
text_editor_newline_bindings,
|
35
18
|
text_editor_to_unbind,
|
36
19
|
)
|
37
|
-
from .formatters import
|
38
|
-
is_bool_like,
|
39
|
-
try_to_bool,
|
40
|
-
)
|
20
|
+
from .formatters import is_bool_like, try_to_bool
|
41
21
|
from .functions import (
|
42
22
|
consecutive_chunks,
|
43
23
|
consecutive_ranges,
|
24
|
+
del_placeholder_dict_key,
|
44
25
|
event_dict,
|
45
26
|
event_has_char_key,
|
46
27
|
event_opens_dropdown_or_checkbox,
|
47
28
|
get_n2a,
|
29
|
+
get_new_indexes,
|
48
30
|
int_x_tuple,
|
49
31
|
is_contiguous,
|
32
|
+
mod_event_val,
|
50
33
|
new_tk_event,
|
51
34
|
num2alpha,
|
52
35
|
rounded_box_coords,
|
53
36
|
stored_event_dict,
|
37
|
+
try_b_index,
|
54
38
|
try_binding,
|
39
|
+
wrap_text,
|
55
40
|
)
|
56
|
-
from .other_classes import
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
Node,
|
61
|
-
TextEditorStorage,
|
62
|
-
)
|
63
|
-
from .text_editor import (
|
64
|
-
TextEditor,
|
65
|
-
)
|
66
|
-
from .types import (
|
67
|
-
AnyIter,
|
68
|
-
)
|
41
|
+
from .other_classes import DotDict, DraggedRowColumn, DropdownStorage, EventDataDict, Node, TextEditorStorage
|
42
|
+
from .sorting import sort_columns_by_row, sort_row
|
43
|
+
from .text_editor import TextEditor
|
44
|
+
from .tksheet_types import AnyIter
|
69
45
|
|
70
46
|
|
71
47
|
class RowIndex(tk.Canvas):
|
72
|
-
def __init__(self,
|
48
|
+
def __init__(self, parent, **kwargs):
|
73
49
|
super().__init__(
|
74
|
-
|
75
|
-
background=
|
50
|
+
parent,
|
51
|
+
background=parent.ops.index_bg,
|
76
52
|
highlightthickness=0,
|
77
53
|
)
|
78
|
-
self.PAR =
|
54
|
+
self.PAR = parent
|
55
|
+
self.ops = self.PAR.ops
|
79
56
|
self.MT = None # is set from within MainTable() __init__
|
80
57
|
self.CH = None # is set from within MainTable() __init__
|
81
58
|
self.TL = None # is set from within TopLeftRectangle() __init__
|
59
|
+
self.new_iid_ctr = -1
|
82
60
|
self.current_width = None
|
83
61
|
self.popup_menu_loc = None
|
84
62
|
self.extra_begin_edit_cell_func = None
|
@@ -99,6 +77,8 @@ class RowIndex(tk.Canvas):
|
|
99
77
|
self.drag_selection_binding_func = None
|
100
78
|
self.ri_extra_begin_drag_drop_func = None
|
101
79
|
self.ri_extra_end_drag_drop_func = None
|
80
|
+
self.ri_extra_begin_sort_cols_func = None
|
81
|
+
self.ri_extra_end_sort_cols_func = None
|
102
82
|
self.extra_double_b1_func = None
|
103
83
|
self.row_height_resize_func = None
|
104
84
|
self.cell_options = {}
|
@@ -170,18 +150,6 @@ class RowIndex(tk.Canvas):
|
|
170
150
|
self.unbind("<Double-Button-1>")
|
171
151
|
self.unbind(rc_binding)
|
172
152
|
|
173
|
-
def tree_reset(self) -> None:
|
174
|
-
# treeview mode
|
175
|
-
self.tree = {}
|
176
|
-
self.tree_open_ids = set()
|
177
|
-
self.tree_rns = {}
|
178
|
-
if self.MT:
|
179
|
-
self.MT.displayed_rows = []
|
180
|
-
self.MT._row_index = []
|
181
|
-
self.MT.data = []
|
182
|
-
self.MT.row_positions = [0]
|
183
|
-
self.MT.saved_row_heights = {}
|
184
|
-
|
185
153
|
def set_width(self, new_width: int, set_TL: bool = False, recreate_selection_boxes: bool = True) -> None:
|
186
154
|
try:
|
187
155
|
self.config(width=new_width)
|
@@ -364,9 +332,9 @@ class RowIndex(tk.Canvas):
|
|
364
332
|
if (
|
365
333
|
self.width_resizing_enabled
|
366
334
|
and not mouse_over_resize
|
367
|
-
and self.
|
335
|
+
and self.ops.auto_resize_row_index is not True
|
368
336
|
and not (
|
369
|
-
self.
|
337
|
+
self.ops.auto_resize_row_index == "empty"
|
370
338
|
and not isinstance(self.MT._row_index, int)
|
371
339
|
and not self.MT._row_index
|
372
340
|
)
|
@@ -421,7 +389,7 @@ class RowIndex(tk.Canvas):
|
|
421
389
|
)
|
422
390
|
elif self.width_resizing_enabled and self.rsz_h is None and self.rsz_w is True:
|
423
391
|
self.set_width_of_index_to_text()
|
424
|
-
elif (self.row_selection_enabled or self.
|
392
|
+
elif (self.row_selection_enabled or self.ops.treeview) and self.rsz_h is None and self.rsz_w is None:
|
425
393
|
r = self.MT.identify_row(y=event.y)
|
426
394
|
if r < len(self.MT.row_positions) - 1:
|
427
395
|
iid = self.event_over_tree_arrow(r, self.canvasy(event.y), event.x)
|
@@ -471,20 +439,22 @@ class RowIndex(tk.Canvas):
|
|
471
439
|
self.current_width,
|
472
440
|
y,
|
473
441
|
width=1,
|
474
|
-
fill=self.
|
475
|
-
tag="rhl",
|
442
|
+
fill=self.ops.resizing_line_fg,
|
443
|
+
tag=("rh", "rhl"),
|
476
444
|
)
|
477
|
-
self.MT.create_resize_line(x1, y, x2, y, width=1, fill=self.
|
445
|
+
self.MT.create_resize_line(x1, y, x2, y, width=1, fill=self.ops.resizing_line_fg, tag=("rh", "rhl"))
|
478
446
|
self.create_resize_line(
|
479
447
|
0,
|
480
448
|
line2y,
|
481
449
|
self.current_width,
|
482
450
|
line2y,
|
483
451
|
width=1,
|
484
|
-
fill=self.
|
485
|
-
tag="rhl2",
|
452
|
+
fill=self.ops.resizing_line_fg,
|
453
|
+
tag=("rh", "rhl2"),
|
454
|
+
)
|
455
|
+
self.MT.create_resize_line(
|
456
|
+
x1, line2y, x2, line2y, width=1, fill=self.ops.resizing_line_fg, tag=("rh", "rhl2")
|
486
457
|
)
|
487
|
-
self.MT.create_resize_line(x1, line2y, x2, line2y, width=1, fill=self.PAR.ops.resizing_line_fg, tag="rhl2")
|
488
458
|
elif self.width_resizing_enabled and self.rsz_h is None and self.rsz_w is True:
|
489
459
|
self.currently_resizing_width = True
|
490
460
|
elif self.MT.identify_row(y=event.y, allow_end=False) is None:
|
@@ -515,7 +485,7 @@ class RowIndex(tk.Canvas):
|
|
515
485
|
if self.height_resizing_enabled and self.rsz_h is not None and self.currently_resizing_height:
|
516
486
|
y = self.canvasy(event.y)
|
517
487
|
size = y - self.MT.row_positions[self.rsz_h - 1]
|
518
|
-
if size >= self.MT.min_row_height and size < self.
|
488
|
+
if size >= self.MT.min_row_height and size < self.ops.max_row_height:
|
519
489
|
self.hide_resize_and_ctrl_lines(ctrl_lines=False)
|
520
490
|
line2y = self.MT.row_positions[self.rsz_h - 1]
|
521
491
|
self.create_resize_line(
|
@@ -524,18 +494,18 @@ class RowIndex(tk.Canvas):
|
|
524
494
|
self.current_width,
|
525
495
|
y,
|
526
496
|
width=1,
|
527
|
-
fill=self.
|
528
|
-
tag="rhl",
|
497
|
+
fill=self.ops.resizing_line_fg,
|
498
|
+
tag=("rh", "rhl"),
|
529
499
|
)
|
530
|
-
self.MT.create_resize_line(x1, y, x2, y, width=1, fill=self.
|
500
|
+
self.MT.create_resize_line(x1, y, x2, y, width=1, fill=self.ops.resizing_line_fg, tag=("rh", "rhl"))
|
531
501
|
self.create_resize_line(
|
532
502
|
0,
|
533
503
|
line2y,
|
534
504
|
self.current_width,
|
535
505
|
line2y,
|
536
506
|
width=1,
|
537
|
-
fill=self.
|
538
|
-
tag="rhl2",
|
507
|
+
fill=self.ops.resizing_line_fg,
|
508
|
+
tag=("rh", "rhl2"),
|
539
509
|
)
|
540
510
|
self.MT.create_resize_line(
|
541
511
|
x1,
|
@@ -543,19 +513,19 @@ class RowIndex(tk.Canvas):
|
|
543
513
|
x2,
|
544
514
|
line2y,
|
545
515
|
width=1,
|
546
|
-
fill=self.
|
547
|
-
tag="rhl2",
|
516
|
+
fill=self.ops.resizing_line_fg,
|
517
|
+
tag=("rh", "rhl2"),
|
548
518
|
)
|
549
519
|
self.drag_height_resize()
|
550
520
|
elif self.width_resizing_enabled and self.rsz_w is not None and self.currently_resizing_width:
|
551
521
|
evx = event.x
|
552
522
|
if evx > self.current_width:
|
553
|
-
if evx > self.
|
554
|
-
evx = int(self.
|
523
|
+
if evx > self.ops.max_index_width:
|
524
|
+
evx = int(self.ops.max_index_width)
|
555
525
|
self.drag_width_resize(evx)
|
556
526
|
else:
|
557
|
-
if evx < self.
|
558
|
-
evx = self.
|
527
|
+
if evx < self.ops.min_column_width:
|
528
|
+
evx = self.ops.min_column_width
|
559
529
|
self.drag_width_resize(evx)
|
560
530
|
elif (
|
561
531
|
self.drag_and_drop_enabled
|
@@ -712,16 +682,16 @@ class RowIndex(tk.Canvas):
|
|
712
682
|
self.current_width,
|
713
683
|
ypos,
|
714
684
|
width=3,
|
715
|
-
fill=self.
|
685
|
+
fill=self.ops.drag_and_drop_bg,
|
716
686
|
tag="move_rows",
|
717
687
|
)
|
718
|
-
self.MT.create_resize_line(x1, ypos, x2, ypos, width=3, fill=self.
|
688
|
+
self.MT.create_resize_line(x1, ypos, x2, ypos, width=3, fill=self.ops.drag_and_drop_bg, tag="move_rows")
|
719
689
|
for chunk in consecutive_chunks(rows):
|
720
690
|
self.MT.show_ctrl_outline(
|
721
691
|
start_cell=(0, chunk[0]),
|
722
692
|
end_cell=(len(self.MT.col_positions) - 1, chunk[-1] + 1),
|
723
693
|
dash=(),
|
724
|
-
outline=self.
|
694
|
+
outline=self.ops.drag_and_drop_bg,
|
725
695
|
delete_on_timer=False,
|
726
696
|
)
|
727
697
|
|
@@ -785,8 +755,8 @@ class RowIndex(tk.Canvas):
|
|
785
755
|
size = new_row_pos - self.MT.row_positions[self.rsz_h - 1]
|
786
756
|
if size < self.MT.min_row_height:
|
787
757
|
new_row_pos = ceil(self.MT.row_positions[self.rsz_h - 1] + self.MT.min_row_height)
|
788
|
-
elif size > self.
|
789
|
-
new_row_pos = floor(self.MT.row_positions[self.rsz_h - 1] + self.
|
758
|
+
elif size > self.ops.max_row_height:
|
759
|
+
new_row_pos = floor(self.MT.row_positions[self.rsz_h - 1] + self.ops.max_row_height)
|
790
760
|
increment = new_row_pos - self.MT.row_positions[self.rsz_h]
|
791
761
|
self.MT.row_positions[self.rsz_h + 1 :] = [
|
792
762
|
e + increment for e in islice(self.MT.row_positions, self.rsz_h + 1, None)
|
@@ -795,7 +765,7 @@ class RowIndex(tk.Canvas):
|
|
795
765
|
new_height = self.MT.row_positions[self.rsz_h] - self.MT.row_positions[self.rsz_h - 1]
|
796
766
|
self.MT.allow_auto_resize_rows = False
|
797
767
|
self.MT.recreate_all_selection_boxes()
|
798
|
-
self.MT.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
|
768
|
+
self.MT.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True, set_scrollregion=False)
|
799
769
|
if self.row_height_resize_func is not None and old_height != new_height:
|
800
770
|
self.row_height_resize_func(
|
801
771
|
event_dict(
|
@@ -821,6 +791,7 @@ class RowIndex(tk.Canvas):
|
|
821
791
|
if self.height_resizing_enabled and self.rsz_h is not None and self.currently_resizing_height:
|
822
792
|
self.drag_height_resize()
|
823
793
|
self.hide_resize_and_ctrl_lines(ctrl_lines=False)
|
794
|
+
self.MT.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
|
824
795
|
elif (
|
825
796
|
self.drag_and_drop_enabled
|
826
797
|
and self.MT.anything_selected(exclude_cells=True, exclude_columns=True)
|
@@ -846,33 +817,28 @@ class RowIndex(tk.Canvas):
|
|
846
817
|
r += 1
|
847
818
|
if r > len(self.MT.row_positions) - 1:
|
848
819
|
r = len(self.MT.row_positions) - 1
|
849
|
-
event_data =
|
850
|
-
|
851
|
-
sheet=self.PAR.name,
|
852
|
-
widget=self,
|
853
|
-
boxes=self.MT.get_boxes(),
|
854
|
-
selected=self.MT.selected,
|
855
|
-
value=r,
|
856
|
-
)
|
820
|
+
event_data = self.MT.new_event_dict("move_rows", state=True)
|
821
|
+
event_data["value"] = r
|
857
822
|
if try_binding(self.ri_extra_begin_drag_drop_func, event_data, "begin_move_rows"):
|
858
823
|
data_new_idxs, disp_new_idxs, event_data = self.MT.move_rows_adjust_options_dict(
|
859
824
|
*self.MT.get_args_for_move_rows(
|
860
825
|
move_to=r,
|
861
826
|
to_move=self.dragged_row.to_move,
|
862
827
|
),
|
863
|
-
move_data=self.
|
864
|
-
move_heights=self.
|
828
|
+
move_data=self.ops.row_drag_and_drop_perform,
|
829
|
+
move_heights=self.ops.row_drag_and_drop_perform,
|
865
830
|
event_data=event_data,
|
866
831
|
)
|
867
|
-
|
868
|
-
"
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
self.MT.
|
873
|
-
|
874
|
-
|
875
|
-
|
832
|
+
if data_new_idxs and disp_new_idxs:
|
833
|
+
event_data["moved"]["rows"] = {
|
834
|
+
"data": data_new_idxs,
|
835
|
+
"displayed": disp_new_idxs,
|
836
|
+
}
|
837
|
+
if self.MT.undo_enabled:
|
838
|
+
self.MT.undo_stack.append(stored_event_dict(event_data))
|
839
|
+
self.MT.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
|
840
|
+
try_binding(self.ri_extra_end_drag_drop_func, event_data, "end_move_rows")
|
841
|
+
self.MT.sheet_modified(event_data)
|
876
842
|
elif self.b1_pressed_loc is not None and self.rsz_w is None and self.rsz_h is None:
|
877
843
|
r = self.MT.identify_row(y=event.y)
|
878
844
|
if (
|
@@ -909,7 +875,7 @@ class RowIndex(tk.Canvas):
|
|
909
875
|
canvasy: float,
|
910
876
|
eventx: int,
|
911
877
|
) -> bool:
|
912
|
-
if self.
|
878
|
+
if self.ops.treeview and (
|
913
879
|
canvasy < self.MT.row_positions[r] + self.MT.index_txt_height + 5
|
914
880
|
and isinstance(self.MT._row_index, list)
|
915
881
|
and (datarn := self.MT.datarn(r)) < len(self.MT._row_index)
|
@@ -920,6 +886,96 @@ class RowIndex(tk.Canvas):
|
|
920
886
|
return iid
|
921
887
|
return None
|
922
888
|
|
889
|
+
def _sort_rows(
|
890
|
+
self,
|
891
|
+
event: tk.Event | None = None,
|
892
|
+
rows: AnyIter[int] | None = None,
|
893
|
+
reverse: bool = False,
|
894
|
+
validation: bool = True,
|
895
|
+
key: Callable | None = None,
|
896
|
+
undo: bool = True,
|
897
|
+
) -> EventDataDict:
|
898
|
+
if rows is None:
|
899
|
+
rows = self.MT.get_selected_rows()
|
900
|
+
if not rows:
|
901
|
+
rows = list(range(0, len(self.MT.row_positions) - 1))
|
902
|
+
event_data = self.MT.new_event_dict("edit_table")
|
903
|
+
try_binding(self.MT.extra_begin_sort_cells_func, event_data)
|
904
|
+
for r in rows:
|
905
|
+
datarn = self.MT.datarn(r)
|
906
|
+
for c, val in enumerate(sort_row(self.MT.data[datarn], reverse=reverse, key=key)):
|
907
|
+
if (
|
908
|
+
not self.MT.edit_validation_func
|
909
|
+
or not validation
|
910
|
+
or (
|
911
|
+
self.MT.edit_validation_func
|
912
|
+
and (val := self.MT.edit_validation_func(mod_event_val(event_data, val, (datarn, c))))
|
913
|
+
is not None
|
914
|
+
)
|
915
|
+
):
|
916
|
+
event_data = self.MT.event_data_set_cell(
|
917
|
+
datarn=datarn,
|
918
|
+
datacn=c,
|
919
|
+
value=val,
|
920
|
+
event_data=event_data,
|
921
|
+
)
|
922
|
+
if event_data["cells"]["table"]:
|
923
|
+
if undo and self.MT.undo_enabled:
|
924
|
+
self.MT.undo_stack.append(stored_event_dict(event_data))
|
925
|
+
try_binding(self.MT.extra_end_sort_cells_func, event_data, "end_edit_table")
|
926
|
+
self.MT.sheet_modified(event_data)
|
927
|
+
self.PAR.emit_event("<<SheetModified>>", event_data)
|
928
|
+
self.MT.refresh()
|
929
|
+
return event_data
|
930
|
+
|
931
|
+
def _sort_columns_by_row(
|
932
|
+
self,
|
933
|
+
event: tk.Event | None = None,
|
934
|
+
row: int | None = None,
|
935
|
+
reverse: bool = False,
|
936
|
+
key: Callable | None = None,
|
937
|
+
undo: bool = True,
|
938
|
+
) -> EventDataDict:
|
939
|
+
event_data = self.MT.new_event_dict("sort_columns", state=True)
|
940
|
+
if not self.MT.data:
|
941
|
+
return event_data
|
942
|
+
if row is None:
|
943
|
+
if not self.MT.selected:
|
944
|
+
return event_data
|
945
|
+
row = self.MT.selected.row
|
946
|
+
if try_binding(self.ri_extra_begin_sort_cols_func, event_data, "begin_sort_columns"):
|
947
|
+
sorted_indices, data_new_idxs = sort_columns_by_row(self.MT.data, row=row, reverse=reverse, key=key)
|
948
|
+
disp_new_idxs = {}
|
949
|
+
if self.MT.all_columns_displayed:
|
950
|
+
disp_new_idxs = data_new_idxs
|
951
|
+
else:
|
952
|
+
col_ctr = 0
|
953
|
+
# idx is the displayed index, can just do range
|
954
|
+
for old_idx in sorted_indices:
|
955
|
+
if (idx := try_b_index(self.MT.displayed_columns, old_idx)) is not None:
|
956
|
+
disp_new_idxs[idx] = col_ctr
|
957
|
+
col_ctr += 1
|
958
|
+
data_new_idxs, disp_new_idxs, _ = self.PAR.mapping_move_columns(
|
959
|
+
data_new_idxs=data_new_idxs,
|
960
|
+
disp_new_idxs=disp_new_idxs,
|
961
|
+
move_data=True,
|
962
|
+
create_selections=False,
|
963
|
+
undo=False,
|
964
|
+
emit_event=False,
|
965
|
+
redraw=True,
|
966
|
+
)
|
967
|
+
event_data["moved"]["columns"] = {
|
968
|
+
"data": data_new_idxs,
|
969
|
+
"displayed": disp_new_idxs,
|
970
|
+
}
|
971
|
+
if undo and self.MT.undo_enabled:
|
972
|
+
self.MT.undo_stack.append(stored_event_dict(event_data))
|
973
|
+
try_binding(self.ri_extra_end_sort_cols_func, event_data, "end_sort_columns")
|
974
|
+
self.MT.sheet_modified(event_data)
|
975
|
+
self.PAR.emit_event("<<SheetModified>>", event_data)
|
976
|
+
self.MT.refresh()
|
977
|
+
return event_data
|
978
|
+
|
923
979
|
def toggle_select_row(
|
924
980
|
self,
|
925
981
|
row: int,
|
@@ -1008,7 +1064,7 @@ class RowIndex(tk.Canvas):
|
|
1008
1064
|
y1,
|
1009
1065
|
x2,
|
1010
1066
|
y2,
|
1011
|
-
radius=5 if self.
|
1067
|
+
radius=5 if self.ops.rounded_boxes else 0,
|
1012
1068
|
)
|
1013
1069
|
if isinstance(iid, int):
|
1014
1070
|
self.coords(iid, coords)
|
@@ -1039,27 +1095,42 @@ class RowIndex(tk.Canvas):
|
|
1039
1095
|
def get_cell_dimensions(self, datarn: int) -> tuple[int, int]:
|
1040
1096
|
txt = self.get_valid_cell_data_as_str(datarn, fix=False)
|
1041
1097
|
if txt:
|
1042
|
-
self.MT.txt_measure_canvas.itemconfig(
|
1043
|
-
self.MT.txt_measure_canvas_text, text=txt, font=self.PAR.ops.index_font
|
1044
|
-
)
|
1098
|
+
self.MT.txt_measure_canvas.itemconfig(self.MT.txt_measure_canvas_text, text=txt, font=self.ops.index_font)
|
1045
1099
|
b = self.MT.txt_measure_canvas.bbox(self.MT.txt_measure_canvas_text)
|
1046
1100
|
w = b[2] - b[0] + 7
|
1047
1101
|
h = b[3] - b[1] + 5
|
1048
1102
|
else:
|
1049
|
-
w = self.
|
1103
|
+
w = self.ops.default_row_index_width
|
1050
1104
|
h = self.MT.min_row_height
|
1051
1105
|
if self.get_cell_kwargs(datarn, key="dropdown") or self.get_cell_kwargs(datarn, key="checkbox"):
|
1052
1106
|
w += self.MT.index_txt_height + 2
|
1053
|
-
if self.
|
1107
|
+
if self.ops.treeview:
|
1054
1108
|
if datarn in self.cell_options and "align" in self.cell_options[datarn]:
|
1055
1109
|
align = self.cell_options[datarn]["align"]
|
1056
1110
|
else:
|
1057
1111
|
align = self.align
|
1058
|
-
if align
|
1112
|
+
if align.endswith("w"):
|
1059
1113
|
w += self.MT.index_txt_height
|
1060
1114
|
w += self.get_iid_indent(self.MT._row_index[datarn].iid) + 10
|
1061
1115
|
return w, h
|
1062
1116
|
|
1117
|
+
def get_wrapped_cell_height(self, datarn: int) -> int:
|
1118
|
+
n_lines = max(
|
1119
|
+
1,
|
1120
|
+
sum(
|
1121
|
+
1
|
1122
|
+
for _ in wrap_text(
|
1123
|
+
text=self.get_valid_cell_data_as_str(datarn, fix=False),
|
1124
|
+
max_width=self.current_width,
|
1125
|
+
max_lines=float("inf"),
|
1126
|
+
char_width_fn=self.wrap_get_char_w,
|
1127
|
+
widths=self.MT.char_widths[self.index_font],
|
1128
|
+
wrap=self.ops.index_wrap,
|
1129
|
+
)
|
1130
|
+
),
|
1131
|
+
)
|
1132
|
+
return 3 + (n_lines * self.MT.index_txt_height)
|
1133
|
+
|
1063
1134
|
def get_row_text_height(
|
1064
1135
|
self,
|
1065
1136
|
row: int,
|
@@ -1069,7 +1140,7 @@ class RowIndex(tk.Canvas):
|
|
1069
1140
|
h = self.MT.min_row_height
|
1070
1141
|
datarn = row if self.MT.all_rows_displayed else self.MT.displayed_rows[row]
|
1071
1142
|
# index
|
1072
|
-
|
1143
|
+
ih = self.get_wrapped_cell_height(datarn)
|
1073
1144
|
# table
|
1074
1145
|
if self.MT.data:
|
1075
1146
|
if self.MT.all_columns_displayed:
|
@@ -1086,20 +1157,22 @@ class RowIndex(tk.Canvas):
|
|
1086
1157
|
else:
|
1087
1158
|
start_col, end_col = 0, len(self.MT.displayed_columns)
|
1088
1159
|
iterable = self.MT.displayed_columns[start_col:end_col]
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1160
|
+
h = max(
|
1161
|
+
h,
|
1162
|
+
max(
|
1163
|
+
self.MT.get_wrapped_cell_height(
|
1164
|
+
datarn,
|
1165
|
+
datacn,
|
1166
|
+
)
|
1167
|
+
for datacn in iterable
|
1168
|
+
),
|
1169
|
+
)
|
1170
|
+
self.MT.cells_cache = None
|
1171
|
+
h = max(h, ih)
|
1096
1172
|
if only_if_too_small and h < self.MT.row_positions[row + 1] - self.MT.row_positions[row]:
|
1097
1173
|
return self.MT.row_positions[row + 1] - self.MT.row_positions[row]
|
1098
|
-
|
1099
|
-
|
1100
|
-
elif h > self.PAR.ops.max_row_height:
|
1101
|
-
h = int(self.PAR.ops.max_row_height)
|
1102
|
-
return h
|
1174
|
+
else:
|
1175
|
+
return max(int(min(h, self.ops.max_row_height)), self.MT.min_row_height)
|
1103
1176
|
|
1104
1177
|
def set_row_height(
|
1105
1178
|
self,
|
@@ -1113,8 +1186,8 @@ class RowIndex(tk.Canvas):
|
|
1113
1186
|
height = self.get_row_text_height(row=row, visible_only=visible_only)
|
1114
1187
|
if height < self.MT.min_row_height:
|
1115
1188
|
height = int(self.MT.min_row_height)
|
1116
|
-
elif height > self.
|
1117
|
-
height = int(self.
|
1189
|
+
elif height > self.ops.max_row_height:
|
1190
|
+
height = int(self.ops.max_row_height)
|
1118
1191
|
if only_if_too_small and height <= self.MT.row_positions[row + 1] - self.MT.row_positions[row]:
|
1119
1192
|
return self.MT.row_positions[row + 1] - self.MT.row_positions[row]
|
1120
1193
|
new_row_pos = self.MT.row_positions[row] + height
|
@@ -1132,7 +1205,7 @@ class RowIndex(tk.Canvas):
|
|
1132
1205
|
only_rows: AnyIter[int] | None = None,
|
1133
1206
|
) -> int:
|
1134
1207
|
self.fix_index()
|
1135
|
-
w = self.
|
1208
|
+
w = self.ops.default_row_index_width
|
1136
1209
|
if (not self.MT._row_index and isinstance(self.MT._row_index, list)) or (
|
1137
1210
|
isinstance(self.MT._row_index, int) and self.MT._row_index >= len(self.MT.data)
|
1138
1211
|
):
|
@@ -1148,8 +1221,8 @@ class RowIndex(tk.Canvas):
|
|
1148
1221
|
iterable = self.MT.displayed_rows
|
1149
1222
|
if (new_w := max(map(itemgetter(0), map(self.get_cell_dimensions, iterable)), default=w)) > w:
|
1150
1223
|
w = new_w
|
1151
|
-
if w > self.
|
1152
|
-
w = int(self.
|
1224
|
+
if w > self.ops.max_index_width:
|
1225
|
+
w = int(self.ops.max_index_width)
|
1153
1226
|
return w
|
1154
1227
|
|
1155
1228
|
def set_width_of_index_to_text(
|
@@ -1158,7 +1231,7 @@ class RowIndex(tk.Canvas):
|
|
1158
1231
|
only_rows: list = [],
|
1159
1232
|
) -> int:
|
1160
1233
|
self.fix_index()
|
1161
|
-
w = self.
|
1234
|
+
w = self.ops.default_row_index_width
|
1162
1235
|
if (text is None and isinstance(self.MT._row_index, list) and not self.MT._row_index) or (
|
1163
1236
|
isinstance(self.MT._row_index, int) and self.MT._row_index >= len(self.MT.data)
|
1164
1237
|
):
|
@@ -1170,8 +1243,8 @@ class RowIndex(tk.Canvas):
|
|
1170
1243
|
w = tw
|
1171
1244
|
elif text is None:
|
1172
1245
|
w = self.get_index_text_width(only_rows=only_rows)
|
1173
|
-
if w > self.
|
1174
|
-
w = int(self.
|
1246
|
+
if w > self.ops.max_index_width:
|
1247
|
+
w = int(self.ops.max_index_width)
|
1175
1248
|
self.set_width(w, set_TL=True)
|
1176
1249
|
self.MT.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
|
1177
1250
|
return w
|
@@ -1200,15 +1273,15 @@ class RowIndex(tk.Canvas):
|
|
1200
1273
|
|
1201
1274
|
def auto_set_index_width(self, end_row: int, only_rows: list) -> bool:
|
1202
1275
|
if not isinstance(self.MT._row_index, int) and not self.MT._row_index:
|
1203
|
-
if self.
|
1204
|
-
new_w = self.MT.get_txt_w(f"{num2alpha(end_row)}") + 20
|
1205
|
-
elif self.
|
1206
|
-
new_w = self.MT.get_txt_w(f"{end_row}") + 20
|
1207
|
-
elif self.
|
1208
|
-
new_w = self.MT.get_txt_w(f"{end_row + 1} {num2alpha(end_row)}") + 20
|
1209
|
-
elif self.
|
1276
|
+
if self.ops.default_row_index == "letters":
|
1277
|
+
new_w = self.MT.get_txt_w(f"{num2alpha(end_row)}", self.index_font) + 20
|
1278
|
+
elif self.ops.default_row_index == "numbers":
|
1279
|
+
new_w = self.MT.get_txt_w(f"{end_row}", self.index_font) + 20
|
1280
|
+
elif self.ops.default_row_index == "both":
|
1281
|
+
new_w = self.MT.get_txt_w(f"{end_row + 1} {num2alpha(end_row)}", self.index_font) + 20
|
1282
|
+
elif self.ops.default_row_index is None:
|
1210
1283
|
new_w = 20
|
1211
|
-
elif self.
|
1284
|
+
elif self.ops.auto_resize_row_index is True:
|
1212
1285
|
new_w = self.get_index_text_width(only_rows=only_rows)
|
1213
1286
|
else:
|
1214
1287
|
new_w = None
|
@@ -1239,8 +1312,8 @@ class RowIndex(tk.Canvas):
|
|
1239
1312
|
fill = color_map[fill]
|
1240
1313
|
if "rows" in selections and r in selections["rows"]:
|
1241
1314
|
txtfg = (
|
1242
|
-
self.
|
1243
|
-
if kwargs[1] is None or self.
|
1315
|
+
self.ops.index_selected_rows_fg
|
1316
|
+
if kwargs[1] is None or self.ops.display_selected_fg_over_highlights
|
1244
1317
|
else kwargs[1]
|
1245
1318
|
)
|
1246
1319
|
if fill:
|
@@ -1251,8 +1324,8 @@ class RowIndex(tk.Canvas):
|
|
1251
1324
|
)
|
1252
1325
|
elif "cells" in selections and r in selections["cells"]:
|
1253
1326
|
txtfg = (
|
1254
|
-
self.
|
1255
|
-
if kwargs[1] is None or self.
|
1327
|
+
self.ops.index_selected_cells_fg
|
1328
|
+
if kwargs[1] is None or self.ops.display_selected_fg_over_highlights
|
1256
1329
|
else kwargs[1]
|
1257
1330
|
)
|
1258
1331
|
if fill:
|
@@ -1262,7 +1335,7 @@ class RowIndex(tk.Canvas):
|
|
1262
1335
|
+ f"{int((int(fill[5:], 16) + int(sel_cells_bg[5:], 16)) / 2):02X}"
|
1263
1336
|
)
|
1264
1337
|
else:
|
1265
|
-
txtfg = self.
|
1338
|
+
txtfg = self.ops.index_fg if kwargs[1] is None else kwargs[1]
|
1266
1339
|
if fill:
|
1267
1340
|
redrawn = self.redraw_highlight(
|
1268
1341
|
0,
|
@@ -1271,8 +1344,8 @@ class RowIndex(tk.Canvas):
|
|
1271
1344
|
sr,
|
1272
1345
|
fill=fill,
|
1273
1346
|
outline=(
|
1274
|
-
self.
|
1275
|
-
if self.get_cell_kwargs(datarn, key="dropdown") and self.
|
1347
|
+
self.ops.index_fg
|
1348
|
+
if self.get_cell_kwargs(datarn, key="dropdown") and self.ops.show_dropdown_borders
|
1276
1349
|
else ""
|
1277
1350
|
),
|
1278
1351
|
tag="s",
|
@@ -1280,14 +1353,14 @@ class RowIndex(tk.Canvas):
|
|
1280
1353
|
tree_arrow_fg = txtfg
|
1281
1354
|
elif not kwargs:
|
1282
1355
|
if "rows" in selections and r in selections["rows"]:
|
1283
|
-
txtfg = self.
|
1284
|
-
tree_arrow_fg = self.
|
1356
|
+
txtfg = self.ops.index_selected_rows_fg
|
1357
|
+
tree_arrow_fg = self.ops.selected_rows_tree_arrow_fg
|
1285
1358
|
elif "cells" in selections and r in selections["cells"]:
|
1286
|
-
txtfg = self.
|
1287
|
-
tree_arrow_fg = self.
|
1359
|
+
txtfg = self.ops.index_selected_cells_fg
|
1360
|
+
tree_arrow_fg = self.ops.selected_cells_tree_arrow_fg
|
1288
1361
|
else:
|
1289
|
-
txtfg = self.
|
1290
|
-
tree_arrow_fg = self.
|
1362
|
+
txtfg = self.ops.index_fg
|
1363
|
+
tree_arrow_fg = self.ops.tree_arrow_fg
|
1291
1364
|
return txtfg, tree_arrow_fg, redrawn
|
1292
1365
|
|
1293
1366
|
def redraw_highlight(
|
@@ -1308,6 +1381,7 @@ class RowIndex(tk.Canvas):
|
|
1308
1381
|
self.itemconfig(iid, fill=fill, outline=outline)
|
1309
1382
|
else:
|
1310
1383
|
self.itemconfig(iid, fill=fill, outline=outline, tag=tag, state="normal")
|
1384
|
+
self.tag_raise(iid)
|
1311
1385
|
else:
|
1312
1386
|
iid = self.create_rectangle(coords, fill=fill, outline=outline, tag=tag)
|
1313
1387
|
self.disp_high[iid] = True
|
@@ -1408,14 +1482,14 @@ class RowIndex(tk.Canvas):
|
|
1408
1482
|
t, sh = self.hidd_tree_arrow.popitem()
|
1409
1483
|
self.coords(t, points)
|
1410
1484
|
if sh:
|
1411
|
-
self.itemconfig(t, fill=fill if has_children else self.
|
1485
|
+
self.itemconfig(t, fill=fill if has_children else self.ops.index_grid_fg)
|
1412
1486
|
else:
|
1413
|
-
self.itemconfig(t, fill=fill if has_children else self.
|
1487
|
+
self.itemconfig(t, fill=fill if has_children else self.ops.index_grid_fg, tag=tag, state="normal")
|
1414
1488
|
self.lift(t)
|
1415
1489
|
else:
|
1416
1490
|
t = self.create_line(
|
1417
1491
|
points,
|
1418
|
-
fill=fill if has_children else self.
|
1492
|
+
fill=fill if has_children else self.ops.index_grid_fg,
|
1419
1493
|
tag=tag,
|
1420
1494
|
width=2,
|
1421
1495
|
capstyle=tk.ROUND,
|
@@ -1436,8 +1510,8 @@ class RowIndex(tk.Canvas):
|
|
1436
1510
|
draw_arrow: bool = True,
|
1437
1511
|
open_: bool = False,
|
1438
1512
|
) -> None:
|
1439
|
-
if draw_outline and self.
|
1440
|
-
self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.
|
1513
|
+
if draw_outline and self.ops.show_dropdown_borders:
|
1514
|
+
self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.ops.index_fg, tag=tag)
|
1441
1515
|
if draw_arrow:
|
1442
1516
|
mod = (self.MT.index_txt_height - 1) if self.MT.index_txt_height % 2 else self.MT.index_txt_height
|
1443
1517
|
small_mod = int(mod / 5)
|
@@ -1523,15 +1597,33 @@ class RowIndex(tk.Canvas):
|
|
1523
1597
|
t = self.create_polygon(points, fill=fill, outline=outline, tag=tag, smooth=True)
|
1524
1598
|
self.disp_checkbox[t] = True
|
1525
1599
|
|
1526
|
-
def configure_scrollregion(self, last_row_line_pos: float) ->
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1600
|
+
def configure_scrollregion(self, last_row_line_pos: float) -> bool:
|
1601
|
+
try:
|
1602
|
+
self.configure(
|
1603
|
+
scrollregion=(
|
1604
|
+
0,
|
1605
|
+
0,
|
1606
|
+
self.current_width,
|
1607
|
+
last_row_line_pos + self.ops.empty_vertical + 2,
|
1608
|
+
)
|
1533
1609
|
)
|
1610
|
+
return True
|
1611
|
+
except Exception:
|
1612
|
+
return False
|
1613
|
+
|
1614
|
+
def wrap_get_char_w(self, c: str) -> int:
|
1615
|
+
self.MT.txt_measure_canvas.itemconfig(
|
1616
|
+
self.MT.txt_measure_canvas_text,
|
1617
|
+
text=_test_str + c,
|
1618
|
+
font=self.index_font,
|
1534
1619
|
)
|
1620
|
+
b = self.MT.txt_measure_canvas.bbox(self.MT.txt_measure_canvas_text)
|
1621
|
+
if c in self.MT.char_widths[self.index_font]:
|
1622
|
+
return self.MT.char_widths[self.index_font][c]
|
1623
|
+
else:
|
1624
|
+
wd = b[2] - b[0] - self.index_test_str_w
|
1625
|
+
self.MT.char_widths[self.index_font][c] = wd
|
1626
|
+
return wd
|
1535
1627
|
|
1536
1628
|
def redraw_grid_and_text(
|
1537
1629
|
self,
|
@@ -1544,11 +1636,11 @@ class RowIndex(tk.Canvas):
|
|
1544
1636
|
text_end_row: int,
|
1545
1637
|
scrollpos_bot: int,
|
1546
1638
|
row_pos_exists: bool,
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1639
|
+
set_scrollregion: bool,
|
1640
|
+
) -> bool:
|
1641
|
+
if set_scrollregion:
|
1642
|
+
if not self.configure_scrollregion(last_row_line_pos=last_row_line_pos):
|
1643
|
+
return False
|
1552
1644
|
self.hidd_text.update(self.disp_text)
|
1553
1645
|
self.disp_text = {}
|
1554
1646
|
self.hidd_high.update(self.disp_high)
|
@@ -1562,59 +1654,33 @@ class RowIndex(tk.Canvas):
|
|
1562
1654
|
self.hidd_tree_arrow.update(self.disp_tree_arrow)
|
1563
1655
|
self.disp_tree_arrow = {}
|
1564
1656
|
self.visible_row_dividers = {}
|
1565
|
-
xend = self.current_width - 6
|
1566
1657
|
self.row_width_resize_bbox = (
|
1567
1658
|
self.current_width - 2,
|
1568
1659
|
scrollpos_top,
|
1569
1660
|
self.current_width,
|
1570
1661
|
scrollpos_bot,
|
1571
1662
|
)
|
1572
|
-
if (self.PAR.ops.show_horizontal_grid or self.height_resizing_enabled) and row_pos_exists:
|
1573
|
-
points = [
|
1574
|
-
self.current_width - 1,
|
1575
|
-
y_stop - 1,
|
1576
|
-
self.current_width - 1,
|
1577
|
-
scrollpos_top - 1,
|
1578
|
-
-1,
|
1579
|
-
scrollpos_top - 1,
|
1580
|
-
]
|
1581
|
-
for r in range(grid_start_row, grid_end_row):
|
1582
|
-
draw_y = self.MT.row_positions[r]
|
1583
|
-
if r and self.height_resizing_enabled:
|
1584
|
-
self.visible_row_dividers[r] = (1, draw_y - 2, xend, draw_y + 2)
|
1585
|
-
points.extend(
|
1586
|
-
(
|
1587
|
-
-1,
|
1588
|
-
draw_y,
|
1589
|
-
self.current_width,
|
1590
|
-
draw_y,
|
1591
|
-
-1,
|
1592
|
-
draw_y,
|
1593
|
-
-1,
|
1594
|
-
self.MT.row_positions[r + 1] if len(self.MT.row_positions) - 1 > r else draw_y,
|
1595
|
-
)
|
1596
|
-
)
|
1597
|
-
self.redraw_gridline(points=points, fill=self.PAR.ops.index_grid_fg, width=1, tag="h")
|
1598
1663
|
sel_cells_bg = (
|
1599
|
-
self.
|
1600
|
-
if self.
|
1601
|
-
else color_map[self.
|
1664
|
+
self.ops.index_selected_cells_bg
|
1665
|
+
if self.ops.index_selected_cells_bg.startswith("#")
|
1666
|
+
else color_map[self.ops.index_selected_cells_bg]
|
1602
1667
|
)
|
1603
1668
|
sel_rows_bg = (
|
1604
|
-
self.
|
1605
|
-
if self.
|
1606
|
-
else color_map[self.
|
1669
|
+
self.ops.index_selected_rows_bg
|
1670
|
+
if self.ops.index_selected_rows_bg.startswith("#")
|
1671
|
+
else color_map[self.ops.index_selected_rows_bg]
|
1607
1672
|
)
|
1608
|
-
font = self.
|
1673
|
+
font = self.ops.index_font
|
1609
1674
|
selections = self.get_redraw_selections(text_start_row, grid_end_row)
|
1610
1675
|
dd_coords = self.dropdown.get_coords()
|
1611
|
-
treeview = self.
|
1612
|
-
|
1676
|
+
treeview = self.ops.treeview
|
1677
|
+
wrap = self.ops.index_wrap
|
1613
1678
|
for r in range(text_start_row, text_end_row):
|
1614
1679
|
rtopgridln = self.MT.row_positions[r]
|
1615
1680
|
rbotgridln = self.MT.row_positions[r + 1]
|
1616
1681
|
if rbotgridln - rtopgridln < self.MT.index_txt_height:
|
1617
1682
|
continue
|
1683
|
+
checkbox_kwargs = {}
|
1618
1684
|
datarn = r if self.MT.all_rows_displayed else self.MT.displayed_rows[r]
|
1619
1685
|
fill, tree_arrow_fg, dd_drawn = self.redraw_highlight_get_text_fg(
|
1620
1686
|
fr=rtopgridln,
|
@@ -1625,103 +1691,71 @@ class RowIndex(tk.Canvas):
|
|
1625
1691
|
selections=selections,
|
1626
1692
|
datarn=datarn,
|
1627
1693
|
)
|
1628
|
-
|
1629
1694
|
if datarn in self.cell_options and "align" in self.cell_options[datarn]:
|
1630
1695
|
align = self.cell_options[datarn]["align"]
|
1631
1696
|
else:
|
1632
1697
|
align = self.align
|
1633
|
-
dropdown_kwargs
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
self.redraw_dropdown(
|
1639
|
-
0,
|
1640
|
-
rtopgridln,
|
1641
|
-
self.current_width - 1,
|
1642
|
-
rbotgridln - 1,
|
1643
|
-
fill=fill if dropdown_kwargs["state"] != "disabled" else self.PAR.ops.index_grid_fg,
|
1644
|
-
outline=fill,
|
1645
|
-
tag="dd",
|
1646
|
-
draw_outline=not dd_drawn,
|
1647
|
-
draw_arrow=True,
|
1648
|
-
open_=dd_coords == r,
|
1649
|
-
)
|
1650
|
-
else:
|
1651
|
-
mw = self.current_width - 2
|
1652
|
-
|
1653
|
-
elif align == "e":
|
1654
|
-
if dropdown_kwargs:
|
1655
|
-
mw = self.current_width - self.MT.index_txt_height - 2
|
1698
|
+
if dropdown_kwargs := self.get_cell_kwargs(datarn, key="dropdown"):
|
1699
|
+
max_width = self.current_width - self.MT.index_txt_height - 2
|
1700
|
+
if align.endswith("w"):
|
1701
|
+
draw_x = 3
|
1702
|
+
elif align.endswith("e"):
|
1656
1703
|
draw_x = self.current_width - 5 - self.MT.index_txt_height
|
1657
|
-
|
1658
|
-
0,
|
1659
|
-
rtopgridln,
|
1660
|
-
self.current_width - 1,
|
1661
|
-
rbotgridln - 1,
|
1662
|
-
fill=fill if dropdown_kwargs["state"] != "disabled" else self.PAR.ops.index_grid_fg,
|
1663
|
-
outline=fill,
|
1664
|
-
tag="dd",
|
1665
|
-
draw_outline=not dd_drawn,
|
1666
|
-
draw_arrow=True,
|
1667
|
-
open_=dd_coords == r,
|
1668
|
-
)
|
1669
|
-
else:
|
1670
|
-
mw = self.current_width - 2
|
1671
|
-
draw_x = self.current_width - 3
|
1672
|
-
|
1673
|
-
elif align == "center":
|
1674
|
-
if dropdown_kwargs:
|
1675
|
-
mw = self.current_width - self.MT.index_txt_height - 2
|
1704
|
+
elif align.endswith("n"):
|
1676
1705
|
draw_x = ceil((self.current_width - self.MT.index_txt_height) / 2)
|
1677
|
-
|
1678
|
-
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
1706
|
+
self.redraw_dropdown(
|
1707
|
+
0,
|
1708
|
+
rtopgridln,
|
1709
|
+
self.current_width - 1,
|
1710
|
+
rbotgridln - 1,
|
1711
|
+
fill=fill if dropdown_kwargs["state"] != "disabled" else self.ops.index_grid_fg,
|
1712
|
+
outline=fill,
|
1713
|
+
tag="dd",
|
1714
|
+
draw_outline=not dd_drawn,
|
1715
|
+
draw_arrow=True,
|
1716
|
+
open_=dd_coords == r,
|
1717
|
+
)
|
1718
|
+
else:
|
1719
|
+
max_width = self.current_width - 2
|
1720
|
+
if align.endswith("w"):
|
1721
|
+
draw_x = 3
|
1722
|
+
elif align.endswith("e"):
|
1723
|
+
draw_x = self.current_width - 3
|
1724
|
+
elif align.endswith("n"):
|
1691
1725
|
draw_x = floor(self.current_width / 2)
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1726
|
+
if (
|
1727
|
+
(checkbox_kwargs := self.get_cell_kwargs(datarn, key="checkbox"))
|
1728
|
+
and not dropdown_kwargs
|
1729
|
+
and max_width > self.MT.index_txt_height + 1
|
1730
|
+
):
|
1731
|
+
box_w = self.MT.index_txt_height + 1
|
1732
|
+
if align.endswith("w"):
|
1733
|
+
draw_x += box_w + 3
|
1734
|
+
elif align.endswith("n"):
|
1735
|
+
draw_x += ceil(box_w / 2) + 1
|
1736
|
+
max_width -= box_w + 4
|
1737
|
+
try:
|
1738
|
+
draw_check = (
|
1739
|
+
self.MT._row_index[datarn]
|
1740
|
+
if isinstance(self.MT._row_index, (list, tuple))
|
1741
|
+
else self.MT.data[datarn][self.MT._row_index]
|
1742
|
+
)
|
1743
|
+
except Exception:
|
1744
|
+
draw_check = False
|
1745
|
+
self.redraw_checkbox(
|
1746
|
+
2,
|
1747
|
+
rtopgridln + 2,
|
1748
|
+
self.MT.index_txt_height + 3,
|
1749
|
+
rtopgridln + self.MT.index_txt_height + 3,
|
1750
|
+
fill=fill if checkbox_kwargs["state"] == "normal" else self.ops.index_grid_fg,
|
1751
|
+
outline="",
|
1752
|
+
tag="cb",
|
1753
|
+
draw_check=draw_check,
|
1708
1754
|
)
|
1709
|
-
except Exception:
|
1710
|
-
draw_check = False
|
1711
|
-
self.redraw_checkbox(
|
1712
|
-
2,
|
1713
|
-
rtopgridln + 2,
|
1714
|
-
self.MT.index_txt_height + 3,
|
1715
|
-
rtopgridln + self.MT.index_txt_height + 3,
|
1716
|
-
fill=fill if checkbox_kwargs["state"] == "normal" else self.PAR.ops.index_grid_fg,
|
1717
|
-
outline="",
|
1718
|
-
tag="cb",
|
1719
|
-
draw_check=draw_check,
|
1720
|
-
)
|
1721
1755
|
if treeview and isinstance(self.MT._row_index, list) and len(self.MT._row_index) > datarn:
|
1722
1756
|
iid = self.MT._row_index[datarn].iid
|
1723
|
-
|
1724
|
-
if align
|
1757
|
+
max_width -= self.MT.index_txt_height
|
1758
|
+
if align.endswith("w"):
|
1725
1759
|
draw_x += self.MT.index_txt_height + 3
|
1726
1760
|
level, indent = self.get_iid_level_indent(iid)
|
1727
1761
|
draw_x += indent + 5
|
@@ -1736,84 +1770,118 @@ class RowIndex(tk.Canvas):
|
|
1736
1770
|
open_=self.MT._row_index[datarn].iid in self.tree_open_ids,
|
1737
1771
|
level=level,
|
1738
1772
|
)
|
1739
|
-
|
1740
|
-
if not lns:
|
1773
|
+
if max_width <= 1:
|
1741
1774
|
continue
|
1742
|
-
|
1743
|
-
if
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1775
|
+
text = self.get_valid_cell_data_as_str(datarn, fix=False)
|
1776
|
+
if not text:
|
1777
|
+
continue
|
1778
|
+
start_line = max(0, int((scrollpos_top - rtopgridln) / self.MT.index_txt_height))
|
1779
|
+
draw_y = rtopgridln + 3 + (start_line * self.MT.index_txt_height)
|
1780
|
+
gen_lines = wrap_text(
|
1781
|
+
text=text,
|
1782
|
+
max_width=max_width,
|
1783
|
+
max_lines=int((rbotgridln - rtopgridln - 2) / self.MT.index_txt_height),
|
1784
|
+
char_width_fn=self.wrap_get_char_w,
|
1785
|
+
widths=self.MT.char_widths[font],
|
1786
|
+
wrap=wrap,
|
1787
|
+
start_line=start_line,
|
1788
|
+
)
|
1789
|
+
if align.endswith(("w", "e")):
|
1790
|
+
if self.hidd_text:
|
1791
|
+
iid, showing = self.hidd_text.popitem()
|
1792
|
+
self.coords(iid, draw_x, draw_y)
|
1793
|
+
if showing:
|
1794
|
+
self.itemconfig(
|
1795
|
+
iid,
|
1796
|
+
text="\n".join(gen_lines),
|
1797
|
+
fill=fill,
|
1798
|
+
font=font,
|
1799
|
+
anchor=align,
|
1800
|
+
)
|
1801
|
+
else:
|
1802
|
+
self.itemconfig(
|
1803
|
+
iid,
|
1804
|
+
text="\n".join(gen_lines),
|
1805
|
+
fill=fill,
|
1806
|
+
font=font,
|
1807
|
+
anchor=align,
|
1808
|
+
state="normal",
|
1809
|
+
)
|
1810
|
+
self.tag_raise(iid)
|
1811
|
+
else:
|
1812
|
+
iid = self.create_text(
|
1813
|
+
draw_x,
|
1814
|
+
draw_y,
|
1815
|
+
text="\n".join(gen_lines),
|
1816
|
+
fill=fill,
|
1817
|
+
font=font,
|
1818
|
+
anchor=align,
|
1819
|
+
tags="t",
|
1820
|
+
)
|
1821
|
+
self.disp_text[iid] = True
|
1822
|
+
else:
|
1823
|
+
for text in gen_lines:
|
1824
|
+
if self.hidd_text:
|
1825
|
+
iid, showing = self.hidd_text.popitem()
|
1826
|
+
self.coords(iid, draw_x, draw_y)
|
1827
|
+
if showing:
|
1828
|
+
self.itemconfig(
|
1829
|
+
iid,
|
1830
|
+
text=text,
|
1831
|
+
fill=fill,
|
1832
|
+
font=font,
|
1833
|
+
anchor=align,
|
1834
|
+
)
|
1773
1835
|
else:
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
text=txt,
|
1836
|
+
self.itemconfig(
|
1837
|
+
iid,
|
1838
|
+
text=text,
|
1778
1839
|
fill=fill,
|
1779
1840
|
font=font,
|
1780
1841
|
anchor=align,
|
1781
|
-
|
1842
|
+
state="normal",
|
1782
1843
|
)
|
1783
|
-
self.
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
1806
|
-
|
1807
|
-
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1812
|
-
|
1813
|
-
|
1814
|
-
draw_y
|
1815
|
-
|
1816
|
-
|
1844
|
+
self.tag_raise(iid)
|
1845
|
+
else:
|
1846
|
+
iid = self.create_text(
|
1847
|
+
draw_x,
|
1848
|
+
draw_y,
|
1849
|
+
text=text,
|
1850
|
+
fill=fill,
|
1851
|
+
font=font,
|
1852
|
+
anchor=align,
|
1853
|
+
tags="t",
|
1854
|
+
)
|
1855
|
+
self.disp_text[iid] = True
|
1856
|
+
draw_y += self.MT.header_txt_height
|
1857
|
+
|
1858
|
+
xend = self.current_width - 6
|
1859
|
+
if (self.ops.show_horizontal_grid or self.height_resizing_enabled) and row_pos_exists:
|
1860
|
+
points = [
|
1861
|
+
self.current_width - 1,
|
1862
|
+
y_stop - 1,
|
1863
|
+
self.current_width - 1,
|
1864
|
+
scrollpos_top - 1,
|
1865
|
+
-1,
|
1866
|
+
scrollpos_top - 1,
|
1867
|
+
]
|
1868
|
+
for r in range(grid_start_row, grid_end_row):
|
1869
|
+
draw_y = self.MT.row_positions[r]
|
1870
|
+
if r and self.height_resizing_enabled:
|
1871
|
+
self.visible_row_dividers[r] = (1, draw_y - 2, xend, draw_y + 2)
|
1872
|
+
points.extend(
|
1873
|
+
(
|
1874
|
+
-1,
|
1875
|
+
draw_y,
|
1876
|
+
self.current_width,
|
1877
|
+
draw_y,
|
1878
|
+
-1,
|
1879
|
+
draw_y,
|
1880
|
+
-1,
|
1881
|
+
self.MT.row_positions[r + 1] if len(self.MT.row_positions) - 1 > r else draw_y,
|
1882
|
+
)
|
1883
|
+
)
|
1884
|
+
self.redraw_gridline(points=points, fill=self.ops.index_grid_fg, width=1, tag="h")
|
1817
1885
|
for dct in (
|
1818
1886
|
self.hidd_text,
|
1819
1887
|
self.hidd_high,
|
@@ -1826,6 +1894,8 @@ class RowIndex(tk.Canvas):
|
|
1826
1894
|
if showing:
|
1827
1895
|
self.itemconfig(iid, state="hidden")
|
1828
1896
|
dct[iid] = False
|
1897
|
+
if self.disp_resize_lines:
|
1898
|
+
self.tag_raise("rh")
|
1829
1899
|
return True
|
1830
1900
|
|
1831
1901
|
def get_redraw_selections(self, startr: int, endr: int) -> dict[str, set[int]]:
|
@@ -1904,14 +1974,14 @@ class RowIndex(tk.Canvas):
|
|
1904
1974
|
return False
|
1905
1975
|
else:
|
1906
1976
|
text = text if isinstance(text, str) else f"{text}"
|
1907
|
-
if self.
|
1977
|
+
if self.ops.cell_auto_resize_enabled:
|
1908
1978
|
self.set_row_height_run_binding(r)
|
1909
1979
|
if self.text_editor.open and r == self.text_editor.row:
|
1910
1980
|
self.text_editor.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
|
1911
1981
|
return False
|
1912
1982
|
self.hide_text_editor()
|
1913
1983
|
if not self.MT.see(r=r, c=0, keep_yscroll=True, check_cell_visibility=True):
|
1914
|
-
self.MT.
|
1984
|
+
self.MT.main_table_redraw_grid_and_text(True, True)
|
1915
1985
|
x = 0
|
1916
1986
|
y = self.MT.row_positions[r]
|
1917
1987
|
w = self.current_width + 1
|
@@ -1919,24 +1989,24 @@ class RowIndex(tk.Canvas):
|
|
1919
1989
|
kwargs = {
|
1920
1990
|
"menu_kwargs": DotDict(
|
1921
1991
|
{
|
1922
|
-
"font": self.
|
1923
|
-
"foreground": self.
|
1924
|
-
"background": self.
|
1925
|
-
"activebackground": self.
|
1926
|
-
"activeforeground": self.
|
1992
|
+
"font": self.ops.index_font,
|
1993
|
+
"foreground": self.ops.popup_menu_fg,
|
1994
|
+
"background": self.ops.popup_menu_bg,
|
1995
|
+
"activebackground": self.ops.popup_menu_highlight_bg,
|
1996
|
+
"activeforeground": self.ops.popup_menu_highlight_fg,
|
1927
1997
|
}
|
1928
1998
|
),
|
1929
|
-
"sheet_ops": self.
|
1930
|
-
"border_color": self.
|
1999
|
+
"sheet_ops": self.ops,
|
2000
|
+
"border_color": self.ops.index_selected_rows_bg,
|
1931
2001
|
"text": text,
|
1932
2002
|
"state": state,
|
1933
2003
|
"width": w,
|
1934
2004
|
"height": h,
|
1935
2005
|
"show_border": True,
|
1936
|
-
"bg": self.
|
1937
|
-
"fg": self.
|
1938
|
-
"select_bg": self.
|
1939
|
-
"select_fg": self.
|
2006
|
+
"bg": self.ops.index_editor_bg,
|
2007
|
+
"fg": self.ops.index_editor_fg,
|
2008
|
+
"select_bg": self.ops.index_editor_select_bg,
|
2009
|
+
"select_fg": self.ops.index_editor_select_fg,
|
1940
2010
|
"align": self.get_cell_align(r),
|
1941
2011
|
"r": r,
|
1942
2012
|
}
|
@@ -1975,13 +2045,13 @@ class RowIndex(tk.Canvas):
|
|
1975
2045
|
> curr_height
|
1976
2046
|
):
|
1977
2047
|
r = self.text_editor.row
|
1978
|
-
new_height = curr_height + self.MT.
|
2048
|
+
new_height = curr_height + self.MT.index_txt_height
|
1979
2049
|
space_bot = self.MT.get_space_bot(r)
|
1980
2050
|
if new_height > space_bot:
|
1981
2051
|
new_height = space_bot
|
1982
2052
|
if new_height != curr_height:
|
1983
2053
|
self.set_row_height(r, new_height)
|
1984
|
-
self.MT.
|
2054
|
+
self.MT.main_table_redraw_grid_and_text(True, True)
|
1985
2055
|
self.text_editor.window.config(height=new_height)
|
1986
2056
|
self.coords(self.text_editor.canvas_id, 0, self.MT.row_positions[r] + 1)
|
1987
2057
|
if self.dropdown.open and self.dropdown.get_coords() == r:
|
@@ -2006,7 +2076,7 @@ class RowIndex(tk.Canvas):
|
|
2006
2076
|
if self.text_editor.open:
|
2007
2077
|
r = self.text_editor.row
|
2008
2078
|
self.text_editor.window.config(height=self.MT.row_positions[r + 1] - self.MT.row_positions[r])
|
2009
|
-
self.text_editor.tktext.config(font=self.
|
2079
|
+
self.text_editor.tktext.config(font=self.ops.index_font)
|
2010
2080
|
self.coords(
|
2011
2081
|
self.text_editor.canvas_id,
|
2012
2082
|
0,
|
@@ -2109,15 +2179,12 @@ class RowIndex(tk.Canvas):
|
|
2109
2179
|
for i, v in enumerate(self.get_cell_kwargs(datarn, key="dropdown")["values"]):
|
2110
2180
|
v_numlines = len(v.split("\n") if isinstance(v, str) else f"{v}".split("\n"))
|
2111
2181
|
if v_numlines > 1:
|
2112
|
-
win_h += (
|
2113
|
-
self.MT.index_first_ln_ins + (v_numlines * self.MT.index_xtra_lines_increment) + 5
|
2114
|
-
) # end of cell
|
2182
|
+
win_h += self.MT.index_txt_height + (v_numlines * self.MT.index_txt_height) + 5 # end of cell
|
2115
2183
|
else:
|
2116
2184
|
win_h += self.MT.min_row_height
|
2117
2185
|
if i == 5:
|
2118
2186
|
break
|
2119
|
-
|
2120
|
-
win_h = 500
|
2187
|
+
win_h = min(win_h, 500)
|
2121
2188
|
space_bot = self.MT.get_space_bot(r, text_editor_h)
|
2122
2189
|
space_top = int(self.MT.row_positions[r])
|
2123
2190
|
anchor = "nw"
|
@@ -2180,15 +2247,15 @@ class RowIndex(tk.Canvas):
|
|
2180
2247
|
reset_kwargs = {
|
2181
2248
|
"r": r,
|
2182
2249
|
"c": 0,
|
2183
|
-
"bg": self.
|
2184
|
-
"fg": self.
|
2185
|
-
"select_bg": self.
|
2186
|
-
"select_fg": self.
|
2250
|
+
"bg": self.ops.index_editor_bg,
|
2251
|
+
"fg": self.ops.index_editor_fg,
|
2252
|
+
"select_bg": self.ops.index_editor_select_bg,
|
2253
|
+
"select_fg": self.ops.index_editor_select_fg,
|
2187
2254
|
"width": win_w,
|
2188
2255
|
"height": win_h,
|
2189
|
-
"font": self.
|
2190
|
-
"ops": self.
|
2191
|
-
"outline_color": self.
|
2256
|
+
"font": self.ops.index_font,
|
2257
|
+
"ops": self.ops,
|
2258
|
+
"outline_color": self.ops.index_selected_rows_bg,
|
2192
2259
|
"align": self.get_cell_align(r),
|
2193
2260
|
"values": kwargs["values"],
|
2194
2261
|
"search_function": kwargs["search_function"],
|
@@ -2200,7 +2267,7 @@ class RowIndex(tk.Canvas):
|
|
2200
2267
|
self.coords(self.dropdown.canvas_id, 0, ypos)
|
2201
2268
|
self.dropdown.window.tkraise()
|
2202
2269
|
else:
|
2203
|
-
self.dropdown.window = self.PAR.
|
2270
|
+
self.dropdown.window = self.PAR._dropdown_cls(
|
2204
2271
|
self.winfo_toplevel(),
|
2205
2272
|
**reset_kwargs,
|
2206
2273
|
single_index="r",
|
@@ -2244,13 +2311,11 @@ class RowIndex(tk.Canvas):
|
|
2244
2311
|
if r is not None and selection is not None:
|
2245
2312
|
datarn = r if self.MT.all_rows_displayed else self.MT.displayed_rows[r]
|
2246
2313
|
kwargs = self.get_cell_kwargs(datarn, key="dropdown")
|
2247
|
-
pre_edit_value = self.get_cell_data(datarn)
|
2248
|
-
edited = False
|
2249
2314
|
event_data = event_dict(
|
2250
2315
|
name="end_edit_index",
|
2251
2316
|
sheet=self.PAR.name,
|
2252
2317
|
widget=self,
|
2253
|
-
cells_header={datarn:
|
2318
|
+
cells_header={datarn: self.get_cell_data(datarn)},
|
2254
2319
|
key="??",
|
2255
2320
|
value=selection,
|
2256
2321
|
loc=r,
|
@@ -2258,16 +2323,12 @@ class RowIndex(tk.Canvas):
|
|
2258
2323
|
boxes=self.MT.get_boxes(),
|
2259
2324
|
selected=self.MT.selected,
|
2260
2325
|
)
|
2261
|
-
|
2262
|
-
|
2263
|
-
if
|
2264
|
-
selection = self.MT.edit_validation_func(event_data)
|
2265
|
-
if selection is not None:
|
2266
|
-
edited = self.set_cell_data_undo(r, datarn=datarn, value=selection, redraw=not redraw)
|
2267
|
-
else:
|
2326
|
+
try_binding(kwargs["select_function"], event_data)
|
2327
|
+
selection = selection if not self.MT.edit_validation_func else self.MT.edit_validation_func(event_data)
|
2328
|
+
if selection is not None:
|
2268
2329
|
edited = self.set_cell_data_undo(r, datarn=datarn, value=selection, redraw=not redraw)
|
2269
|
-
|
2270
|
-
|
2330
|
+
if edited:
|
2331
|
+
try_binding(self.extra_end_edit_cell_func, event_data)
|
2271
2332
|
self.MT.recreate_all_selection_boxes()
|
2272
2333
|
self.focus_set()
|
2273
2334
|
self.hide_text_editor_and_dropdown(redraw=redraw)
|
@@ -2343,7 +2404,7 @@ class RowIndex(tk.Canvas):
|
|
2343
2404
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
2344
2405
|
self.set_cell_data(datarn=datarn, value=value)
|
2345
2406
|
edited = True
|
2346
|
-
if edited and cell_resize and self.
|
2407
|
+
if edited and cell_resize and self.ops.cell_auto_resize_enabled:
|
2347
2408
|
self.set_row_height_run_binding(r, only_if_too_small=False)
|
2348
2409
|
if redraw:
|
2349
2410
|
self.MT.refresh()
|
@@ -2358,7 +2419,7 @@ class RowIndex(tk.Canvas):
|
|
2358
2419
|
self.fix_index(datarn)
|
2359
2420
|
if self.get_cell_kwargs(datarn, key="checkbox"):
|
2360
2421
|
self.MT._row_index[datarn] = try_to_bool(value)
|
2361
|
-
elif self.
|
2422
|
+
elif self.ops.treeview:
|
2362
2423
|
self.MT._row_index[datarn].text = value
|
2363
2424
|
else:
|
2364
2425
|
self.MT._row_index[datarn] = value
|
@@ -2400,7 +2461,7 @@ class RowIndex(tk.Canvas):
|
|
2400
2461
|
or (self.MT._row_index[datarn] is None and none_to_empty_str)
|
2401
2462
|
):
|
2402
2463
|
return ""
|
2403
|
-
if self.
|
2464
|
+
if self.ops.treeview:
|
2404
2465
|
return self.MT._row_index[datarn].text
|
2405
2466
|
return self.MT._row_index[datarn]
|
2406
2467
|
|
@@ -2418,14 +2479,23 @@ class RowIndex(tk.Canvas):
|
|
2418
2479
|
if fix:
|
2419
2480
|
self.fix_index(datarn)
|
2420
2481
|
try:
|
2421
|
-
value =
|
2482
|
+
value = self.MT._row_index[datarn]
|
2483
|
+
if value is None:
|
2484
|
+
value = ""
|
2485
|
+
elif isinstance(value, Node):
|
2486
|
+
value = value.text
|
2487
|
+
elif not isinstance(value, str):
|
2488
|
+
value = f"{value}"
|
2422
2489
|
except Exception:
|
2423
2490
|
value = ""
|
2424
|
-
if not value and self.
|
2425
|
-
value = get_n2a(datarn, self.
|
2491
|
+
if not value and self.ops.show_default_index_for_empty:
|
2492
|
+
value = get_n2a(datarn, self.ops.default_row_index)
|
2426
2493
|
return value
|
2427
2494
|
|
2428
2495
|
def get_value_for_empty_cell(self, datarn: int, r_ops: bool = True) -> object:
|
2496
|
+
if self.ops.treeview:
|
2497
|
+
iid = self.new_iid()
|
2498
|
+
return Node(text=iid, iid=iid, parent=self.get_row_parent(datarn))
|
2429
2499
|
if self.get_cell_kwargs(datarn, key="checkbox", cell=r_ops):
|
2430
2500
|
return False
|
2431
2501
|
kwargs = self.get_cell_kwargs(datarn, key="dropdown", cell=r_ops)
|
@@ -2505,63 +2575,378 @@ class RowIndex(tk.Canvas):
|
|
2505
2575
|
|
2506
2576
|
# Treeview Mode
|
2507
2577
|
|
2578
|
+
def tree_reset(self) -> None:
|
2579
|
+
self.tree: dict[str, Node] = {}
|
2580
|
+
self.tree_open_ids = set()
|
2581
|
+
self.tree_rns = {}
|
2582
|
+
if self.MT:
|
2583
|
+
self.MT.displayed_rows = []
|
2584
|
+
self.MT._row_index = []
|
2585
|
+
self.MT.data = []
|
2586
|
+
self.MT.row_positions = [0]
|
2587
|
+
self.MT.saved_row_heights = {}
|
2588
|
+
|
2589
|
+
def new_iid(self) -> str:
|
2590
|
+
self.new_iid_ctr += 1
|
2591
|
+
while (iid := f"{num2alpha(self.new_iid_ctr)}") in self.tree:
|
2592
|
+
self.new_iid_ctr += 1
|
2593
|
+
return iid
|
2594
|
+
|
2595
|
+
def get_row_parent(self, r: int) -> str:
|
2596
|
+
if r >= len(self.MT._row_index):
|
2597
|
+
return ""
|
2598
|
+
else:
|
2599
|
+
return self.MT._row_index[r].parent
|
2600
|
+
|
2601
|
+
def tree_del_rows(self, event_data: EventDataDict) -> EventDataDict:
|
2602
|
+
event_data["treeview"]["nodes"] = {}
|
2603
|
+
for node in reversed(event_data["deleted"]["index"].values()):
|
2604
|
+
iid = node.iid
|
2605
|
+
if parent_node := self.parent_node(iid):
|
2606
|
+
if parent_node.iid not in event_data["treeview"]["nodes"]:
|
2607
|
+
event_data["treeview"]["nodes"][parent_node.iid] = Node(
|
2608
|
+
text=parent_node.text,
|
2609
|
+
iid=parent_node.iid,
|
2610
|
+
parent=parent_node.parent,
|
2611
|
+
children=parent_node.children.copy(),
|
2612
|
+
)
|
2613
|
+
self.remove_iid_from_parents_children(iid)
|
2614
|
+
for node in reversed(event_data["deleted"]["index"].values()):
|
2615
|
+
iid = node.iid
|
2616
|
+
for did in self.get_iid_descendants(iid):
|
2617
|
+
self.tree_open_ids.discard(did)
|
2618
|
+
del self.tree[did]
|
2619
|
+
self.tree_open_ids.discard(iid)
|
2620
|
+
del self.tree[iid]
|
2621
|
+
return event_data
|
2622
|
+
|
2623
|
+
def tree_add_rows(self, event_data: EventDataDict) -> EventDataDict:
|
2624
|
+
for rn, node in event_data["added"]["rows"]["index"].items():
|
2625
|
+
self.tree[node.iid] = node
|
2626
|
+
self.tree_rns[node.iid] = rn
|
2627
|
+
if event_data["treeview"]["nodes"]:
|
2628
|
+
self.restore_nodes(event_data=event_data)
|
2629
|
+
else:
|
2630
|
+
row, a_node = next(reversed(event_data["added"]["rows"]["index"].items()))
|
2631
|
+
if parent := a_node.parent:
|
2632
|
+
if self.tree[parent].children:
|
2633
|
+
index = next(
|
2634
|
+
(i for i, cid in enumerate(self.tree[parent].children) if self.tree_rns[cid] >= row),
|
2635
|
+
len(self.tree[parent].children),
|
2636
|
+
)
|
2637
|
+
self.tree[parent].children[index:index] = [
|
2638
|
+
n.iid for n in reversed(event_data["added"]["rows"]["index"].values())
|
2639
|
+
]
|
2640
|
+
else:
|
2641
|
+
self.tree[parent].children.extend(
|
2642
|
+
n.iid for n in reversed(event_data["added"]["rows"]["index"].values())
|
2643
|
+
)
|
2644
|
+
if not self.PAR.item_displayed(parent) or parent not in self.tree_open_ids:
|
2645
|
+
self.PAR.hide_rows(event_data["added"]["rows"]["index"], data_indexes=True)
|
2646
|
+
return event_data
|
2647
|
+
|
2648
|
+
def move_rows_mod_nodes(
|
2649
|
+
self,
|
2650
|
+
data_new_idxs: dict[int, int],
|
2651
|
+
data_old_idxs: dict[int, int],
|
2652
|
+
disp_new_idxs: dict[int, int],
|
2653
|
+
maxidx: int,
|
2654
|
+
event_data: EventDataDict,
|
2655
|
+
undo_modification: EventDataDict | None = None,
|
2656
|
+
node_change: tuple[str, str, int] | None = None,
|
2657
|
+
) -> Generator[tuple[dict[int, int], dict[int, int], dict[str, int], EventDataDict]] | None:
|
2658
|
+
# data_new_idxs is {old: new, old: new}
|
2659
|
+
# data_old_idxs is {new: old, new: old}
|
2660
|
+
if not event_data["treeview"]["nodes"]:
|
2661
|
+
if undo_modification:
|
2662
|
+
"""
|
2663
|
+
Used by undo/redo
|
2664
|
+
"""
|
2665
|
+
event_data = self.copy_nodes(undo_modification["treeview"]["nodes"], event_data)
|
2666
|
+
self.restore_nodes(undo_modification)
|
2667
|
+
|
2668
|
+
elif event_data["moved"]["rows"]:
|
2669
|
+
if node_change:
|
2670
|
+
item = node_change[0]
|
2671
|
+
moved_rows = [self.tree_rns[item]]
|
2672
|
+
new_parent = node_change[1]
|
2673
|
+
move_to_index = node_change[2]
|
2674
|
+
if new_parent:
|
2675
|
+
move_to_index = (
|
2676
|
+
move_to_index if isinstance(move_to_index, int) else len(self.tree[new_parent].children)
|
2677
|
+
)
|
2678
|
+
move_to_row = self.tree_rns[new_parent] + max(
|
2679
|
+
0, min(move_to_index, len(self.tree[new_parent].children))
|
2680
|
+
)
|
2681
|
+
else:
|
2682
|
+
num_top_nodes = sum(1 for _ in self.gen_top_nodes())
|
2683
|
+
if move_to_index is None:
|
2684
|
+
move_to_row = self.PAR.top_index_row(num_top_nodes - 1)
|
2685
|
+
move_to_index = num_top_nodes
|
2686
|
+
else:
|
2687
|
+
move_to_row = self.PAR.top_index_row(move_to_index)
|
2688
|
+
if move_to_row is None:
|
2689
|
+
move_to_row = self.PAR.top_index_row(num_top_nodes - 1)
|
2690
|
+
move_to_index = num_top_nodes
|
2691
|
+
|
2692
|
+
move_to_iid = self.MT._row_index[move_to_row].iid
|
2693
|
+
insert_row = move_to_row + 1
|
2694
|
+
disp_insert_row = None
|
2695
|
+
|
2696
|
+
else:
|
2697
|
+
iids = set(self.MT._row_index[r].iid for r in event_data["moved"]["rows"]["data"])
|
2698
|
+
iids_descendants = {iid: set(self.get_iid_descendants(iid)) for iid in iids}
|
2699
|
+
|
2700
|
+
# remove descendants in iids to move
|
2701
|
+
iids -= set.union(*iids_descendants.values()) & iids
|
2702
|
+
moved_rows = sorted(map(self.tree_rns.__getitem__, iids))
|
2703
|
+
item = self.MT._row_index[moved_rows[0]].iid
|
2704
|
+
|
2705
|
+
if isinstance(event_data.value, int):
|
2706
|
+
disp_insert_row = event_data.value
|
2707
|
+
if disp_insert_row >= len(self.MT.displayed_rows):
|
2708
|
+
insert_row = len(self.MT._row_index)
|
2709
|
+
else:
|
2710
|
+
insert_row = self.MT.datarn(disp_insert_row)
|
2711
|
+
move_to_iid = self.MT._row_index[min(insert_row, len(self.MT._row_index) - 1)].iid
|
2712
|
+
|
2713
|
+
else:
|
2714
|
+
disp_insert_row = None
|
2715
|
+
min_from = min(event_data["moved"]["rows"]["data"])
|
2716
|
+
# max_from = max(event_data.moved.rows)
|
2717
|
+
min_to = min(event_data["moved"]["rows"]["data"].values())
|
2718
|
+
max_to = max(event_data["moved"]["rows"]["data"].values())
|
2719
|
+
if min_from <= min_to:
|
2720
|
+
insert_row = max_to
|
2721
|
+
else:
|
2722
|
+
insert_row = min_to
|
2723
|
+
move_to_iid = self.MT._row_index[insert_row].iid
|
2724
|
+
|
2725
|
+
move_to_index = self.PAR.index(move_to_iid)
|
2726
|
+
new_parent = self.items_parent(move_to_iid)
|
2727
|
+
|
2728
|
+
event_data["moved"]["rows"]["data"] = {moved_rows[0]: insert_row}
|
2729
|
+
|
2730
|
+
new_loc_is_displayed = not new_parent or (
|
2731
|
+
new_parent and new_parent in self.tree_open_ids and self.PAR.item_displayed(new_parent)
|
2732
|
+
)
|
2733
|
+
# deal with displayed mapping
|
2734
|
+
event_data["moved"]["rows"]["displayed"] = {}
|
2735
|
+
if new_loc_is_displayed:
|
2736
|
+
if disp_insert_row is None:
|
2737
|
+
if new_parent == self.tree[item].parent:
|
2738
|
+
disp_insert_row = self.MT.disprn(self.tree_rns[move_to_iid]) + 1
|
2739
|
+
else:
|
2740
|
+
disp_insert_row = self.MT.disprn(self.tree_rns[move_to_iid]) + 1
|
2741
|
+
if (disp_from_row := self.MT.try_disprn(self.tree_rns[item])) is not None:
|
2742
|
+
event_data["moved"]["rows"]["displayed"] = {disp_from_row: disp_insert_row}
|
2743
|
+
else:
|
2744
|
+
event_data["moved"]["rows"]["displayed"] = {tuple(): disp_insert_row}
|
2745
|
+
|
2746
|
+
if any(self.move_pid_causes_recursive_loop(self.MT._row_index[r].iid, new_parent) for r in moved_rows):
|
2747
|
+
event_data["moved"]["rows"] = {}
|
2748
|
+
data_new_idxs, data_old_idxs, disp_new_idxs = {}, {}, {}
|
2749
|
+
|
2750
|
+
else:
|
2751
|
+
for r in moved_rows:
|
2752
|
+
iid = self.MT._row_index[r].iid
|
2753
|
+
event_data = self.move_node(
|
2754
|
+
event_data=event_data,
|
2755
|
+
item=iid,
|
2756
|
+
parent=new_parent,
|
2757
|
+
index=move_to_index,
|
2758
|
+
)
|
2759
|
+
move_to_index += 1
|
2760
|
+
|
2761
|
+
event_data["moved"]["rows"]["data"] = get_new_indexes(
|
2762
|
+
insert_row,
|
2763
|
+
event_data["moved"]["rows"]["data"],
|
2764
|
+
)
|
2765
|
+
data_new_idxs = event_data["moved"]["rows"]["data"]
|
2766
|
+
data_old_idxs = dict(zip(data_new_idxs.values(), data_new_idxs))
|
2767
|
+
|
2768
|
+
if tuple() in event_data["moved"]["rows"]["displayed"]:
|
2769
|
+
del event_data["moved"]["rows"]["displayed"][tuple()]
|
2770
|
+
|
2771
|
+
if event_data["moved"]["rows"]["displayed"]:
|
2772
|
+
event_data["moved"]["rows"]["displayed"] = get_new_indexes(
|
2773
|
+
disp_insert_row,
|
2774
|
+
event_data["moved"]["rows"]["displayed"],
|
2775
|
+
)
|
2776
|
+
disp_new_idxs = event_data["moved"]["rows"]["displayed"]
|
2777
|
+
|
2778
|
+
if data_new_idxs:
|
2779
|
+
self.MT.move_rows_data(data_new_idxs, data_old_idxs, maxidx)
|
2780
|
+
|
2781
|
+
yield data_new_idxs, data_old_idxs, disp_new_idxs, event_data
|
2782
|
+
|
2783
|
+
if not undo_modification and data_new_idxs:
|
2784
|
+
if new_parent and (not self.PAR.item_displayed(new_parent) or new_parent not in self.tree_open_ids):
|
2785
|
+
self.PAR.hide_rows(set(data_new_idxs.values()), data_indexes=True)
|
2786
|
+
|
2787
|
+
if new_loc_is_displayed:
|
2788
|
+
self.PAR.show_rows(
|
2789
|
+
(r for r in data_new_idxs.values() if self.ancestors_all_open(self.MT._row_index[r].iid))
|
2790
|
+
)
|
2791
|
+
|
2792
|
+
yield None
|
2793
|
+
|
2794
|
+
def move_node(
|
2795
|
+
self,
|
2796
|
+
event_data: EventDataDict,
|
2797
|
+
item: str,
|
2798
|
+
parent: str | None = None,
|
2799
|
+
index: int = 0,
|
2800
|
+
) -> EventDataDict:
|
2801
|
+
# also backs up nodes
|
2802
|
+
if parent is None:
|
2803
|
+
parent = self.items_parent(item)
|
2804
|
+
|
2805
|
+
item_node = self.tree[item]
|
2806
|
+
|
2807
|
+
# new parent is an item
|
2808
|
+
if parent:
|
2809
|
+
parent_node = self.tree[parent]
|
2810
|
+
# its the same parent, we're just moving index
|
2811
|
+
if parent == item_node.parent:
|
2812
|
+
event_data = self.copy_nodes((item, parent), event_data)
|
2813
|
+
pop_index = parent_node.children.index(item)
|
2814
|
+
parent_node.children.insert(index, parent_node.children.pop(pop_index))
|
2815
|
+
|
2816
|
+
else:
|
2817
|
+
if item_node.parent:
|
2818
|
+
event_data = self.copy_nodes((item, item_node.parent, parent), event_data)
|
2819
|
+
else:
|
2820
|
+
event_data = self.copy_nodes((item, parent), event_data)
|
2821
|
+
self.remove_iid_from_parents_children(item)
|
2822
|
+
item_node.parent = parent_node.iid
|
2823
|
+
parent_node.children.insert(index, item)
|
2824
|
+
|
2825
|
+
# no new parent
|
2826
|
+
else:
|
2827
|
+
if item_node.parent:
|
2828
|
+
event_data = self.copy_nodes((item, item_node.parent), event_data)
|
2829
|
+
else:
|
2830
|
+
event_data = self.copy_nodes((item,), event_data)
|
2831
|
+
self.remove_iid_from_parents_children(item)
|
2832
|
+
self.tree[item].parent = ""
|
2833
|
+
|
2834
|
+
# last row in mapping is where to start from +1
|
2835
|
+
mapping = event_data["moved"]["rows"]["data"]
|
2836
|
+
row_ctr = next(reversed(mapping.values())) + 1
|
2837
|
+
|
2838
|
+
if disp_mapping := event_data["moved"]["rows"]["displayed"]:
|
2839
|
+
if tuple() in disp_mapping:
|
2840
|
+
disp_row_ctr = next(reversed(disp_mapping.values()))
|
2841
|
+
else:
|
2842
|
+
disp_row_ctr = next(reversed(disp_mapping.values())) + 1
|
2843
|
+
|
2844
|
+
rn = self.tree_rns[item]
|
2845
|
+
if rn not in mapping:
|
2846
|
+
mapping[rn] = row_ctr
|
2847
|
+
row_ctr += 1
|
2848
|
+
if disp_mapping and (disp_from := self.MT.try_disprn(rn)) is not None:
|
2849
|
+
disp_mapping = del_placeholder_dict_key(disp_mapping, disp_from, disp_row_ctr)
|
2850
|
+
disp_row_ctr += 1
|
2851
|
+
|
2852
|
+
for did in self.get_iid_descendants(item):
|
2853
|
+
mapping[self.tree_rns[did]] = row_ctr
|
2854
|
+
row_ctr += 1
|
2855
|
+
if disp_mapping and (disp_from := self.MT.try_disprn(self.tree_rns[did])) is not None:
|
2856
|
+
disp_mapping = del_placeholder_dict_key(disp_mapping, disp_from, disp_row_ctr)
|
2857
|
+
disp_row_ctr += 1
|
2858
|
+
|
2859
|
+
event_data["moved"]["rows"]["data"] = mapping
|
2860
|
+
event_data["moved"]["rows"]["displayed"] = disp_mapping
|
2861
|
+
|
2862
|
+
return event_data
|
2863
|
+
|
2864
|
+
def restore_nodes(self, event_data: EventDataDict) -> None:
|
2865
|
+
for iid, node in event_data["treeview"]["nodes"].items():
|
2866
|
+
self.MT._row_index[self.tree_rns[iid]] = node
|
2867
|
+
self.tree[iid] = node
|
2868
|
+
|
2869
|
+
def copy_node(self, item: str) -> Node:
|
2870
|
+
n = self.tree[item]
|
2871
|
+
return Node(
|
2872
|
+
text=n.text,
|
2873
|
+
iid=n.iid,
|
2874
|
+
parent=n.parent,
|
2875
|
+
children=n.children.copy(),
|
2876
|
+
)
|
2877
|
+
|
2878
|
+
def copy_nodes(self, items: AnyIter[str], event_data: EventDataDict) -> EventDataDict:
|
2879
|
+
nodes = event_data["treeview"]["nodes"]
|
2880
|
+
for iid in items:
|
2881
|
+
if iid not in nodes:
|
2882
|
+
n = self.tree[iid]
|
2883
|
+
nodes[iid] = Node(
|
2884
|
+
text=n.text,
|
2885
|
+
iid=n.iid,
|
2886
|
+
parent=n.parent,
|
2887
|
+
children=n.children.copy(),
|
2888
|
+
)
|
2889
|
+
return event_data
|
2890
|
+
|
2508
2891
|
def get_node_level(self, node: Node, level: int = 0) -> Generator[int]:
|
2509
2892
|
yield level
|
2510
2893
|
if node.parent:
|
2511
|
-
yield from self.get_node_level(node.parent, level + 1)
|
2894
|
+
yield from self.get_node_level(self.tree[node.parent], level + 1)
|
2512
2895
|
|
2513
|
-
def ancestors_all_open(self, iid: str, stop_at: str
|
2896
|
+
def ancestors_all_open(self, iid: str, stop_at: str = "") -> bool:
|
2514
2897
|
if stop_at:
|
2515
|
-
stop_at = stop_at.iid
|
2516
2898
|
for iid in self.get_iid_ancestors(iid):
|
2517
2899
|
if iid == stop_at:
|
2518
2900
|
return True
|
2519
|
-
|
2901
|
+
elif iid not in self.tree_open_ids:
|
2520
2902
|
return False
|
2521
2903
|
return True
|
2522
2904
|
return all(map(self.tree_open_ids.__contains__, self.get_iid_ancestors(iid)))
|
2523
2905
|
|
2524
2906
|
def get_iid_ancestors(self, iid: str) -> Generator[str]:
|
2525
2907
|
if self.tree[iid].parent:
|
2526
|
-
yield self.tree[iid].parent
|
2527
|
-
yield from self.get_iid_ancestors(self.tree[iid].parent
|
2908
|
+
yield self.tree[iid].parent
|
2909
|
+
yield from self.get_iid_ancestors(self.tree[iid].parent)
|
2528
2910
|
|
2529
2911
|
def get_iid_descendants(self, iid: str, check_open: bool = False) -> Generator[str]:
|
2530
|
-
for
|
2531
|
-
yield
|
2532
|
-
if
|
2533
|
-
|
2534
|
-
):
|
2535
|
-
yield from self.get_iid_descendants(cnode.iid, check_open)
|
2912
|
+
for ciid in self.tree[iid].children:
|
2913
|
+
yield ciid
|
2914
|
+
if self.tree[ciid].children and (not check_open or ciid in self.tree_open_ids):
|
2915
|
+
yield from self.get_iid_descendants(ciid, check_open)
|
2536
2916
|
|
2537
2917
|
def items_parent(self, iid: str) -> str:
|
2538
2918
|
if self.tree[iid].parent:
|
2539
|
-
return self.tree[iid].parent
|
2919
|
+
return self.tree[iid].parent
|
2920
|
+
return ""
|
2921
|
+
|
2922
|
+
def parent_node(self, iid: str) -> Node:
|
2923
|
+
if self.tree[iid].parent:
|
2924
|
+
return self.tree[self.tree[iid].parent]
|
2540
2925
|
return ""
|
2541
2926
|
|
2542
2927
|
def gen_top_nodes(self) -> Generator[Node]:
|
2543
2928
|
yield from (node for node in self.MT._row_index if node.parent == "")
|
2544
2929
|
|
2545
2930
|
def get_iid_indent(self, iid: str) -> int:
|
2546
|
-
if isinstance(self.
|
2547
|
-
indent = self.MT.index_txt_width * int(self.
|
2931
|
+
if isinstance(self.ops.treeview_indent, str):
|
2932
|
+
indent = self.MT.index_txt_width * int(self.ops.treeview_indent)
|
2548
2933
|
else:
|
2549
|
-
indent = self.
|
2934
|
+
indent = self.ops.treeview_indent
|
2550
2935
|
return indent * max(self.get_node_level(self.tree[iid]))
|
2551
2936
|
|
2552
2937
|
def get_iid_level_indent(self, iid: str) -> tuple[int, int]:
|
2553
|
-
if isinstance(self.
|
2554
|
-
indent = self.MT.index_txt_width * int(self.
|
2938
|
+
if isinstance(self.ops.treeview_indent, str):
|
2939
|
+
indent = self.MT.index_txt_width * int(self.ops.treeview_indent)
|
2555
2940
|
else:
|
2556
|
-
indent = self.
|
2941
|
+
indent = self.ops.treeview_indent
|
2557
2942
|
level = max(self.get_node_level(self.tree[iid]))
|
2558
2943
|
return level, indent * level
|
2559
2944
|
|
2560
|
-
def
|
2561
|
-
if
|
2562
|
-
|
2563
|
-
if not
|
2564
|
-
self.tree_open_ids.discard(
|
2945
|
+
def remove_iid_from_parents_children(self, iid: str) -> None:
|
2946
|
+
if parent_node := self.parent_node(iid):
|
2947
|
+
parent_node.children.remove(iid)
|
2948
|
+
if not parent_node.children:
|
2949
|
+
self.tree_open_ids.discard(parent_node.iid)
|
2565
2950
|
|
2566
2951
|
def build_pid_causes_recursive_loop(self, iid: str, pid: str) -> bool:
|
2567
2952
|
return any(
|
@@ -2575,4 +2960,121 @@ class RowIndex(tk.Canvas):
|
|
2575
2960
|
def move_pid_causes_recursive_loop(self, to_move_iid: str, move_to_parent: str) -> bool:
|
2576
2961
|
# if the parent the item is being moved under is one of the item's descendants
|
2577
2962
|
# then it is a recursive loop
|
2578
|
-
return
|
2963
|
+
return to_move_iid == move_to_parent or any(
|
2964
|
+
move_to_parent == diid for diid in self.get_iid_descendants(to_move_iid)
|
2965
|
+
)
|
2966
|
+
|
2967
|
+
def tree_build(
|
2968
|
+
self,
|
2969
|
+
data: list[list[object]],
|
2970
|
+
iid_column: int,
|
2971
|
+
parent_column: int,
|
2972
|
+
text_column: None | int | list[str] = None,
|
2973
|
+
push_ops: bool = False,
|
2974
|
+
row_heights: Sequence[int] | None | False = None,
|
2975
|
+
open_ids: AnyIter[str] | None = None,
|
2976
|
+
safety: bool = True,
|
2977
|
+
ncols: int | None = None,
|
2978
|
+
lower: bool = False,
|
2979
|
+
include_iid_column: bool = True,
|
2980
|
+
include_parent_column: bool = True,
|
2981
|
+
include_text_column: bool = True,
|
2982
|
+
) -> None:
|
2983
|
+
self.PAR.reset(cell_options=False, column_widths=False, header=False, redraw=False)
|
2984
|
+
if text_column is None:
|
2985
|
+
text_column = iid_column
|
2986
|
+
tally_of_ids = defaultdict(lambda: -1)
|
2987
|
+
if not isinstance(ncols, int):
|
2988
|
+
ncols = max(map(len, data), default=0)
|
2989
|
+
for rn, row in enumerate(data):
|
2990
|
+
if safety and ncols > (lnr := len(row)):
|
2991
|
+
row += self.MT.get_empty_row_seq(rn, end=ncols, start=lnr)
|
2992
|
+
if lower:
|
2993
|
+
iid = row[iid_column].lower()
|
2994
|
+
pid = row[parent_column].lower()
|
2995
|
+
else:
|
2996
|
+
iid = row[iid_column]
|
2997
|
+
pid = row[parent_column]
|
2998
|
+
if safety:
|
2999
|
+
if not iid:
|
3000
|
+
continue
|
3001
|
+
tally_of_ids[iid] += 1
|
3002
|
+
if tally_of_ids[iid]:
|
3003
|
+
x = 1
|
3004
|
+
while iid in tally_of_ids:
|
3005
|
+
new = f"{row[iid_column]}_DUPLICATED_{x}"
|
3006
|
+
iid = new.lower() if lower else new
|
3007
|
+
x += 1
|
3008
|
+
tally_of_ids[iid] += 1
|
3009
|
+
row[iid_column] = new
|
3010
|
+
if iid in self.tree:
|
3011
|
+
self.tree[iid].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
3012
|
+
else:
|
3013
|
+
self.tree[iid] = Node(row[text_column] if isinstance(text_column, int) else text_column[rn], iid, "")
|
3014
|
+
if safety and (iid == pid or self.build_pid_causes_recursive_loop(iid, pid)):
|
3015
|
+
row[parent_column] = ""
|
3016
|
+
pid = ""
|
3017
|
+
if pid:
|
3018
|
+
if pid in self.tree:
|
3019
|
+
self.tree[pid].children.append(iid)
|
3020
|
+
else:
|
3021
|
+
self.tree[pid] = Node(
|
3022
|
+
text=row[text_column] if isinstance(text_column, int) else text_column[rn],
|
3023
|
+
iid=pid,
|
3024
|
+
children=[iid],
|
3025
|
+
)
|
3026
|
+
self.tree[iid].parent = pid
|
3027
|
+
else:
|
3028
|
+
self.tree[iid].parent = ""
|
3029
|
+
self.tree_rns[iid] = rn
|
3030
|
+
if safety:
|
3031
|
+
for n in self.tree.values():
|
3032
|
+
if n.parent is None:
|
3033
|
+
n.parent = ""
|
3034
|
+
newrow = self.MT.get_empty_row_seq(len(data), ncols)
|
3035
|
+
newrow[iid_column] = n.iid
|
3036
|
+
self.tree_rns[n.iid] = len(data)
|
3037
|
+
data.append(newrow)
|
3038
|
+
insert_rows = partial(
|
3039
|
+
self.PAR.insert_rows,
|
3040
|
+
idx=0,
|
3041
|
+
heights={} if row_heights is False else row_heights,
|
3042
|
+
row_index=True,
|
3043
|
+
create_selections=False,
|
3044
|
+
fill=False,
|
3045
|
+
undo=False,
|
3046
|
+
push_ops=push_ops,
|
3047
|
+
redraw=False,
|
3048
|
+
)
|
3049
|
+
exclude = set()
|
3050
|
+
if not include_iid_column:
|
3051
|
+
exclude.add(iid_column)
|
3052
|
+
if not include_parent_column:
|
3053
|
+
exclude.add(parent_column)
|
3054
|
+
if isinstance(text_column, int) and not include_text_column:
|
3055
|
+
exclude.add(text_column)
|
3056
|
+
if exclude:
|
3057
|
+
insert_rows(
|
3058
|
+
rows=[
|
3059
|
+
[self.tree[iid]] + [e for i, e in enumerate(data[self.tree_rns[iid]]) if i not in exclude]
|
3060
|
+
for iid in self.PAR.get_iids()
|
3061
|
+
],
|
3062
|
+
tree=False,
|
3063
|
+
)
|
3064
|
+
else:
|
3065
|
+
insert_rows(
|
3066
|
+
rows=[[self.tree[iid]] + data[self.tree_rns[iid]] for iid in self.PAR.get_iids()],
|
3067
|
+
tree=False,
|
3068
|
+
)
|
3069
|
+
self.MT.all_rows_displayed = False
|
3070
|
+
self.MT.displayed_rows = list(range(len(self.MT._row_index)))
|
3071
|
+
self.tree_rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
3072
|
+
if open_ids:
|
3073
|
+
self.PAR.tree_set_open(open_ids=open_ids)
|
3074
|
+
else:
|
3075
|
+
self.PAR.hide_rows(
|
3076
|
+
{self.tree_rns[iid] for iid in self.PAR.get_children() if self.tree[iid].parent},
|
3077
|
+
deselect_all=False,
|
3078
|
+
data_indexes=True,
|
3079
|
+
row_heights=False if row_heights is False else True,
|
3080
|
+
)
|