tksheet 7.4.12__py3-none-any.whl → 7.4.14__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 +1 -1
- tksheet/column_headers.py +109 -94
- tksheet/find_window.py +2 -0
- tksheet/functions.py +17 -5
- tksheet/main_table.py +559 -510
- tksheet/other_classes.py +1 -1
- tksheet/row_index.py +241 -197
- tksheet/sheet.py +24 -16
- {tksheet-7.4.12.dist-info → tksheet-7.4.14.dist-info}/METADATA +7 -7
- tksheet-7.4.14.dist-info/RECORD +22 -0
- tksheet-7.4.12.dist-info/RECORD +0 -22
- {tksheet-7.4.12.dist-info → tksheet-7.4.14.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.4.12.dist-info → tksheet-7.4.14.dist-info}/WHEEL +0 -0
- {tksheet-7.4.12.dist-info → tksheet-7.4.14.dist-info}/top_level.txt +0 -0
tksheet/row_index.py
CHANGED
@@ -3,10 +3,11 @@ from __future__ import annotations
|
|
3
3
|
import tkinter as tk
|
4
4
|
from collections import defaultdict
|
5
5
|
from collections.abc import Callable, Generator, Hashable, Iterator, Sequence
|
6
|
+
from contextlib import suppress
|
6
7
|
from functools import partial
|
7
|
-
from itertools import
|
8
|
-
from math import ceil
|
9
|
-
from
|
8
|
+
from itertools import cycle, islice, repeat
|
9
|
+
from math import ceil
|
10
|
+
from re import findall
|
10
11
|
from typing import Any, Literal
|
11
12
|
|
12
13
|
from .colors import color_map
|
@@ -758,7 +759,7 @@ class RowIndex(tk.Canvas):
|
|
758
759
|
if size < self.MT.min_row_height:
|
759
760
|
new_row_pos = ceil(self.MT.row_positions[self.rsz_h - 1] + self.MT.min_row_height)
|
760
761
|
elif size > self.ops.max_row_height:
|
761
|
-
new_row_pos =
|
762
|
+
new_row_pos = int(self.MT.row_positions[self.rsz_h - 1] + self.ops.max_row_height)
|
762
763
|
increment = new_row_pos - self.MT.row_positions[self.rsz_h]
|
763
764
|
self.MT.row_positions[self.rsz_h + 1 :] = [
|
764
765
|
e + increment for e in islice(self.MT.row_positions, self.rsz_h + 1, None)
|
@@ -1057,25 +1058,48 @@ class RowIndex(tk.Canvas):
|
|
1057
1058
|
def get_cell_dimensions(self, datarn: int) -> tuple[int, int]:
|
1058
1059
|
txt = self.cell_str(datarn, fix=False)
|
1059
1060
|
if txt:
|
1060
|
-
|
1061
|
-
|
1062
|
-
w =
|
1063
|
-
h = b[3] - b[1] + 5
|
1061
|
+
lines = findall(r"[^\n]+", txt)
|
1062
|
+
h = self.MT.index_txt_height * len(lines) + 5
|
1063
|
+
w = max(sum(self.wrap_get_char_w(c) for c in line) for line in lines) + 8
|
1064
1064
|
else:
|
1065
1065
|
w = self.ops.default_row_index_width
|
1066
1066
|
h = self.MT.min_row_height
|
1067
|
-
|
1067
|
+
# self.get_cell_kwargs not used here to boost performance
|
1068
|
+
if (datarn in self.cell_options and "dropdown" in self.cell_options[datarn]) or (
|
1069
|
+
datarn in self.cell_options and "checkbox" in self.cell_options[datarn]
|
1070
|
+
):
|
1068
1071
|
w += self.MT.index_txt_height + 2
|
1069
1072
|
if self.ops.treeview:
|
1070
1073
|
if datarn in self.cell_options and "align" in self.cell_options[datarn]:
|
1071
1074
|
align = self.cell_options[datarn]["align"]
|
1072
1075
|
else:
|
1073
1076
|
align = self.align
|
1074
|
-
if align
|
1077
|
+
if align[-1] == "w":
|
1075
1078
|
w += self.MT.index_txt_height
|
1076
1079
|
w += self.get_iid_indent(self.MT._row_index[datarn].iid) + 10
|
1077
1080
|
return w, h
|
1078
1081
|
|
1082
|
+
def get_cell_width(self, datarn: int) -> int:
|
1083
|
+
txt = self.cell_str(datarn, fix=False)
|
1084
|
+
if txt:
|
1085
|
+
w = max(sum(self.wrap_get_char_w(c) for c in line) for line in findall(r"[^\n]+", txt)) + 8
|
1086
|
+
else:
|
1087
|
+
w = self.ops.default_row_index_width
|
1088
|
+
# self.get_cell_kwargs not used here to boost performance
|
1089
|
+
if (datarn in self.cell_options and "dropdown" in self.cell_options[datarn]) or (
|
1090
|
+
datarn in self.cell_options and "checkbox" in self.cell_options[datarn]
|
1091
|
+
):
|
1092
|
+
w += self.MT.index_txt_height + 2
|
1093
|
+
if self.ops.treeview:
|
1094
|
+
if datarn in self.cell_options and "align" in self.cell_options[datarn]:
|
1095
|
+
align = self.cell_options[datarn]["align"]
|
1096
|
+
else:
|
1097
|
+
align = self.align
|
1098
|
+
if align[-1] == "w":
|
1099
|
+
w += self.MT.index_txt_height
|
1100
|
+
w += self.get_iid_indent(self.MT._row_index[datarn].iid) + 10
|
1101
|
+
return w
|
1102
|
+
|
1079
1103
|
def get_wrapped_cell_height(self, datarn: int) -> int:
|
1080
1104
|
n_lines = max(
|
1081
1105
|
1,
|
@@ -1160,10 +1184,7 @@ class RowIndex(tk.Canvas):
|
|
1160
1184
|
self.MT.recreate_all_selection_boxes()
|
1161
1185
|
return height
|
1162
1186
|
|
1163
|
-
def get_index_text_width(
|
1164
|
-
self,
|
1165
|
-
only_rows: Iterator[int] | None = None,
|
1166
|
-
) -> int:
|
1187
|
+
def get_index_text_width(self, only_rows: Iterator[int] | None = None) -> int:
|
1167
1188
|
self.fix_index()
|
1168
1189
|
w = self.ops.default_row_index_width
|
1169
1190
|
if (not self.MT._row_index and isinstance(self.MT._row_index, list)) or (
|
@@ -1179,7 +1200,7 @@ class RowIndex(tk.Canvas):
|
|
1179
1200
|
iterable = range(len(self.MT.data))
|
1180
1201
|
else:
|
1181
1202
|
iterable = self.MT.displayed_rows
|
1182
|
-
if (new_w := max(map(
|
1203
|
+
if (new_w := max(map(self.get_cell_width, iterable), default=w)) > w:
|
1183
1204
|
w = new_w
|
1184
1205
|
if w > self.ops.max_index_width:
|
1185
1206
|
w = int(self.ops.max_index_width)
|
@@ -1234,18 +1255,18 @@ class RowIndex(tk.Canvas):
|
|
1234
1255
|
def auto_set_index_width(self, end_row: int, only_rows: list) -> bool:
|
1235
1256
|
if not isinstance(self.MT._row_index, int) and not self.MT._row_index:
|
1236
1257
|
if self.ops.default_row_index == "letters":
|
1237
|
-
new_w = self.
|
1258
|
+
new_w = sum(self.wrap_get_char_w(c) for c in num2alpha(end_row)) + 20
|
1238
1259
|
elif self.ops.default_row_index == "numbers":
|
1239
|
-
new_w = self.
|
1260
|
+
new_w = sum(self.wrap_get_char_w(c) for c in str(end_row)) + 20
|
1240
1261
|
elif self.ops.default_row_index == "both":
|
1241
|
-
new_w = self.
|
1262
|
+
new_w = sum(self.wrap_get_char_w(c) for c in f"{end_row + 1} {num2alpha(end_row)}") + 20
|
1242
1263
|
elif self.ops.default_row_index is None:
|
1243
1264
|
new_w = 20
|
1244
1265
|
elif self.ops.auto_resize_row_index is True:
|
1245
1266
|
new_w = self.get_index_text_width(only_rows=only_rows)
|
1246
1267
|
else:
|
1247
1268
|
new_w = None
|
1248
|
-
if new_w is not None and (sheet_w_x :=
|
1269
|
+
if new_w is not None and (sheet_w_x := int(self.PAR.winfo_width() * 0.7)) < new_w:
|
1249
1270
|
new_w = sheet_w_x
|
1250
1271
|
if new_w and (self.current_width - new_w > 20 or new_w - self.current_width > 3):
|
1251
1272
|
if self.MT.find_window.open:
|
@@ -1305,7 +1326,6 @@ class RowIndex(tk.Canvas):
|
|
1305
1326
|
sr,
|
1306
1327
|
fill=fill,
|
1307
1328
|
outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
|
1308
|
-
tag="s",
|
1309
1329
|
)
|
1310
1330
|
tree_arrow_fg = txtfg
|
1311
1331
|
elif not kwargs:
|
@@ -1319,7 +1339,6 @@ class RowIndex(tk.Canvas):
|
|
1319
1339
|
sr,
|
1320
1340
|
fill=self.ops.index_selected_rows_bg,
|
1321
1341
|
outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
|
1322
|
-
tag="s",
|
1323
1342
|
)
|
1324
1343
|
elif "cells" in selections and r in selections["cells"]:
|
1325
1344
|
txtfg = self.ops.index_selected_cells_fg
|
@@ -1331,7 +1350,6 @@ class RowIndex(tk.Canvas):
|
|
1331
1350
|
sr,
|
1332
1351
|
fill=self.ops.index_selected_cells_bg,
|
1333
1352
|
outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
|
1334
|
-
tag="s",
|
1335
1353
|
)
|
1336
1354
|
else:
|
1337
1355
|
txtfg = self.ops.index_fg
|
@@ -1346,7 +1364,6 @@ class RowIndex(tk.Canvas):
|
|
1346
1364
|
y2: float,
|
1347
1365
|
fill: str,
|
1348
1366
|
outline: str,
|
1349
|
-
tag: str | tuple[str],
|
1350
1367
|
) -> bool:
|
1351
1368
|
coords = (x1, y1, x2, y2)
|
1352
1369
|
if self.hidd_high:
|
@@ -1355,10 +1372,9 @@ class RowIndex(tk.Canvas):
|
|
1355
1372
|
if showing:
|
1356
1373
|
self.itemconfig(iid, fill=fill, outline=outline)
|
1357
1374
|
else:
|
1358
|
-
self.itemconfig(iid, fill=fill, outline=outline,
|
1359
|
-
self.tag_raise(iid)
|
1375
|
+
self.itemconfig(iid, fill=fill, outline=outline, state="normal")
|
1360
1376
|
else:
|
1361
|
-
iid = self.create_rectangle(coords, fill=fill, outline=outline
|
1377
|
+
iid = self.create_rectangle(coords, fill=fill, outline=outline)
|
1362
1378
|
self.disp_high[iid] = True
|
1363
1379
|
return True
|
1364
1380
|
|
@@ -1367,18 +1383,17 @@ class RowIndex(tk.Canvas):
|
|
1367
1383
|
points: tuple[float],
|
1368
1384
|
fill: str,
|
1369
1385
|
width: int,
|
1370
|
-
tag: str | tuple[str],
|
1371
1386
|
) -> None:
|
1372
1387
|
if self.hidd_grid:
|
1373
1388
|
t, sh = self.hidd_grid.popitem()
|
1374
1389
|
self.coords(t, points)
|
1375
1390
|
if sh:
|
1376
|
-
self.itemconfig(t, fill=fill, width=width
|
1391
|
+
self.itemconfig(t, fill=fill, width=width)
|
1377
1392
|
else:
|
1378
|
-
self.itemconfig(t, fill=fill, width=width,
|
1393
|
+
self.itemconfig(t, fill=fill, width=width, state="normal")
|
1379
1394
|
self.disp_grid[t] = True
|
1380
1395
|
else:
|
1381
|
-
self.disp_grid[self.create_line(points, fill=fill, width=width
|
1396
|
+
self.disp_grid[self.create_line(points, fill=fill, width=width)] = True
|
1382
1397
|
|
1383
1398
|
def redraw_tree_arrow(
|
1384
1399
|
self,
|
@@ -1386,7 +1401,6 @@ class RowIndex(tk.Canvas):
|
|
1386
1401
|
y1: float,
|
1387
1402
|
y2: float,
|
1388
1403
|
fill: str,
|
1389
|
-
tag: str | tuple[str],
|
1390
1404
|
indent: float,
|
1391
1405
|
has_children: bool = False,
|
1392
1406
|
open_: bool = False,
|
@@ -1394,7 +1408,7 @@ class RowIndex(tk.Canvas):
|
|
1394
1408
|
) -> None:
|
1395
1409
|
mod = (self.MT.index_txt_height - 1) if self.MT.index_txt_height % 2 else self.MT.index_txt_height
|
1396
1410
|
small_mod = int(mod / 5)
|
1397
|
-
mid_y =
|
1411
|
+
mid_y = int(self.MT.min_row_height / 2)
|
1398
1412
|
if has_children:
|
1399
1413
|
# up arrow
|
1400
1414
|
if open_:
|
@@ -1459,16 +1473,15 @@ class RowIndex(tk.Canvas):
|
|
1459
1473
|
if sh:
|
1460
1474
|
self.itemconfig(t, fill=fill if has_children else self.ops.index_grid_fg)
|
1461
1475
|
else:
|
1462
|
-
self.itemconfig(t, fill=fill if has_children else self.ops.index_grid_fg,
|
1463
|
-
self.lift(t)
|
1476
|
+
self.itemconfig(t, fill=fill if has_children else self.ops.index_grid_fg, state="normal")
|
1464
1477
|
else:
|
1465
1478
|
t = self.create_line(
|
1466
1479
|
points,
|
1467
1480
|
fill=fill if has_children else self.ops.index_grid_fg,
|
1468
|
-
tag=tag,
|
1469
1481
|
width=2,
|
1470
1482
|
capstyle=tk.ROUND,
|
1471
1483
|
joinstyle=tk.BEVEL,
|
1484
|
+
tag="lift",
|
1472
1485
|
)
|
1473
1486
|
self.disp_tree_arrow[t] = True
|
1474
1487
|
|
@@ -1480,17 +1493,16 @@ class RowIndex(tk.Canvas):
|
|
1480
1493
|
y2: float,
|
1481
1494
|
fill: str,
|
1482
1495
|
outline: str,
|
1483
|
-
tag: str | tuple[str],
|
1484
1496
|
draw_outline: bool = True,
|
1485
1497
|
draw_arrow: bool = True,
|
1486
1498
|
open_: bool = False,
|
1487
1499
|
) -> None:
|
1488
1500
|
if draw_outline and self.ops.show_dropdown_borders:
|
1489
|
-
self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.ops.index_fg
|
1501
|
+
self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.ops.index_fg)
|
1490
1502
|
if draw_arrow:
|
1491
1503
|
mod = (self.MT.index_txt_height - 1) if self.MT.index_txt_height % 2 else self.MT.index_txt_height
|
1492
1504
|
small_mod = int(mod / 5)
|
1493
|
-
mid_y =
|
1505
|
+
mid_y = int(self.MT.min_row_height / 2)
|
1494
1506
|
if open_:
|
1495
1507
|
# up arrow
|
1496
1508
|
points = (
|
@@ -1517,16 +1529,15 @@ class RowIndex(tk.Canvas):
|
|
1517
1529
|
if sh:
|
1518
1530
|
self.itemconfig(t, fill=fill)
|
1519
1531
|
else:
|
1520
|
-
self.itemconfig(t, fill=fill,
|
1521
|
-
self.lift(t)
|
1532
|
+
self.itemconfig(t, fill=fill, state="normal")
|
1522
1533
|
else:
|
1523
1534
|
t = self.create_line(
|
1524
1535
|
points,
|
1525
1536
|
fill=fill,
|
1526
|
-
tag=tag,
|
1527
1537
|
width=2,
|
1528
1538
|
capstyle=tk.ROUND,
|
1529
1539
|
joinstyle=tk.BEVEL,
|
1540
|
+
tag="lift",
|
1530
1541
|
)
|
1531
1542
|
self.disp_dropdown[t] = True
|
1532
1543
|
|
@@ -1538,7 +1549,6 @@ class RowIndex(tk.Canvas):
|
|
1538
1549
|
y2: float,
|
1539
1550
|
fill: str,
|
1540
1551
|
outline: str,
|
1541
|
-
tag: str | tuple[str],
|
1542
1552
|
draw_check: bool = False,
|
1543
1553
|
) -> None:
|
1544
1554
|
points = rounded_box_coords(x1, y1, x2, y2)
|
@@ -1548,10 +1558,9 @@ class RowIndex(tk.Canvas):
|
|
1548
1558
|
if sh:
|
1549
1559
|
self.itemconfig(t, fill=outline, outline=fill)
|
1550
1560
|
else:
|
1551
|
-
self.itemconfig(t, fill=outline, outline=fill,
|
1552
|
-
self.lift(t)
|
1561
|
+
self.itemconfig(t, fill=outline, outline=fill, state="normal")
|
1553
1562
|
else:
|
1554
|
-
t = self.create_polygon(points, fill=outline, outline=fill,
|
1563
|
+
t = self.create_polygon(points, fill=outline, outline=fill, smooth=True, tag="lift")
|
1555
1564
|
self.disp_checkbox[t] = True
|
1556
1565
|
if draw_check:
|
1557
1566
|
# draw filled box
|
@@ -1566,10 +1575,9 @@ class RowIndex(tk.Canvas):
|
|
1566
1575
|
if sh:
|
1567
1576
|
self.itemconfig(t, fill=fill, outline=outline)
|
1568
1577
|
else:
|
1569
|
-
self.itemconfig(t, fill=fill, outline=outline,
|
1570
|
-
self.lift(t)
|
1578
|
+
self.itemconfig(t, fill=fill, outline=outline, state="normal")
|
1571
1579
|
else:
|
1572
|
-
t = self.create_polygon(points, fill=fill, outline=outline,
|
1580
|
+
t = self.create_polygon(points, fill=fill, outline=outline, smooth=True, tag="lift")
|
1573
1581
|
self.disp_checkbox[t] = True
|
1574
1582
|
|
1575
1583
|
def configure_scrollregion(self, last_row_line_pos: float) -> bool:
|
@@ -1587,15 +1595,15 @@ class RowIndex(tk.Canvas):
|
|
1587
1595
|
return False
|
1588
1596
|
|
1589
1597
|
def wrap_get_char_w(self, c: str) -> int:
|
1590
|
-
self.MT.txt_measure_canvas.itemconfig(
|
1591
|
-
self.MT.txt_measure_canvas_text,
|
1592
|
-
text=_test_str + c,
|
1593
|
-
font=self.index_font,
|
1594
|
-
)
|
1595
|
-
b = self.MT.txt_measure_canvas.bbox(self.MT.txt_measure_canvas_text)
|
1596
1598
|
if c in self.MT.char_widths[self.index_font]:
|
1597
1599
|
return self.MT.char_widths[self.index_font][c]
|
1598
1600
|
else:
|
1601
|
+
self.MT.txt_measure_canvas.itemconfig(
|
1602
|
+
self.MT.txt_measure_canvas_text,
|
1603
|
+
text=_test_str + c,
|
1604
|
+
font=self.index_font,
|
1605
|
+
)
|
1606
|
+
b = self.MT.txt_measure_canvas.bbox(self.MT.txt_measure_canvas_text)
|
1599
1607
|
wd = b[2] - b[0] - self.index_test_str_w
|
1600
1608
|
self.MT.char_widths[self.index_font][c] = wd
|
1601
1609
|
return wd
|
@@ -1634,6 +1642,35 @@ class RowIndex(tk.Canvas):
|
|
1634
1642
|
self.current_width,
|
1635
1643
|
scrollpos_bot,
|
1636
1644
|
)
|
1645
|
+
|
1646
|
+
if (self.ops.show_horizontal_grid or self.height_resizing_enabled) and row_pos_exists:
|
1647
|
+
xend = self.current_width - 6
|
1648
|
+
points = [
|
1649
|
+
self.current_width - 1,
|
1650
|
+
y_stop - 1,
|
1651
|
+
self.current_width - 1,
|
1652
|
+
scrollpos_top - 1,
|
1653
|
+
-1,
|
1654
|
+
scrollpos_top - 1,
|
1655
|
+
]
|
1656
|
+
for r in range(grid_start_row, grid_end_row):
|
1657
|
+
draw_y = self.MT.row_positions[r]
|
1658
|
+
if r and self.height_resizing_enabled:
|
1659
|
+
self.visible_row_dividers[r] = (1, draw_y - 2, xend, draw_y + 2)
|
1660
|
+
points.extend(
|
1661
|
+
(
|
1662
|
+
-1,
|
1663
|
+
draw_y,
|
1664
|
+
self.current_width,
|
1665
|
+
draw_y,
|
1666
|
+
-1,
|
1667
|
+
draw_y,
|
1668
|
+
-1,
|
1669
|
+
self.MT.row_positions[r + 1] if len(self.MT.row_positions) - 1 > r else draw_y,
|
1670
|
+
)
|
1671
|
+
)
|
1672
|
+
self.redraw_gridline(points=points, fill=self.ops.index_grid_fg, width=1)
|
1673
|
+
|
1637
1674
|
sel_cells_bg = (
|
1638
1675
|
self.ops.index_selected_cells_bg
|
1639
1676
|
if self.ops.index_selected_cells_bg.startswith("#")
|
@@ -1673,13 +1710,13 @@ class RowIndex(tk.Canvas):
|
|
1673
1710
|
else:
|
1674
1711
|
align = self.align
|
1675
1712
|
if dropdown_kwargs:
|
1676
|
-
max_width = self.current_width - self.MT.index_txt_height -
|
1677
|
-
if align
|
1713
|
+
max_width = self.current_width - self.MT.index_txt_height - 5
|
1714
|
+
if align[-1] == "w":
|
1678
1715
|
draw_x = 3
|
1679
|
-
elif align
|
1716
|
+
elif align[-1] == "e":
|
1680
1717
|
draw_x = self.current_width - 5 - self.MT.index_txt_height
|
1681
|
-
elif align
|
1682
|
-
draw_x =
|
1718
|
+
elif align[-1] == "n":
|
1719
|
+
draw_x = (self.current_width - self.MT.index_txt_height) / 2
|
1683
1720
|
self.redraw_dropdown(
|
1684
1721
|
0,
|
1685
1722
|
rtopgridln,
|
@@ -1687,29 +1724,28 @@ class RowIndex(tk.Canvas):
|
|
1687
1724
|
rbotgridln - 1,
|
1688
1725
|
fill=fill if dropdown_kwargs["state"] != "disabled" else self.ops.index_grid_fg,
|
1689
1726
|
outline=fill,
|
1690
|
-
tag="dd",
|
1691
1727
|
draw_outline=not dd_drawn,
|
1692
1728
|
draw_arrow=True,
|
1693
1729
|
open_=dd_coords == r,
|
1694
1730
|
)
|
1695
1731
|
else:
|
1696
1732
|
max_width = self.current_width - 2
|
1697
|
-
if align
|
1733
|
+
if align[-1] == "w":
|
1698
1734
|
draw_x = 3
|
1699
|
-
elif align
|
1735
|
+
elif align[-1] == "e":
|
1700
1736
|
draw_x = self.current_width - 3
|
1701
|
-
elif align
|
1702
|
-
draw_x =
|
1737
|
+
elif align[-1] == "n":
|
1738
|
+
draw_x = self.current_width / 2
|
1703
1739
|
if (
|
1704
1740
|
(checkbox_kwargs := self.get_cell_kwargs(datarn, key="checkbox"))
|
1705
1741
|
and not dropdown_kwargs
|
1706
1742
|
and max_width > self.MT.index_txt_height + 1
|
1707
1743
|
):
|
1708
1744
|
box_w = self.MT.index_txt_height + 1
|
1709
|
-
if align
|
1745
|
+
if align[-1] == "w":
|
1710
1746
|
draw_x += box_w + 3
|
1711
|
-
elif align
|
1712
|
-
draw_x +=
|
1747
|
+
elif align[-1] == "n":
|
1748
|
+
draw_x += box_w / 2 + 1
|
1713
1749
|
max_width -= box_w + 4
|
1714
1750
|
try:
|
1715
1751
|
draw_check = (
|
@@ -1726,13 +1762,12 @@ class RowIndex(tk.Canvas):
|
|
1726
1762
|
rtopgridln + self.MT.index_txt_height + 3,
|
1727
1763
|
fill=fill if checkbox_kwargs["state"] == "normal" else self.ops.index_grid_fg,
|
1728
1764
|
outline="",
|
1729
|
-
tag="cb",
|
1730
1765
|
draw_check=draw_check,
|
1731
1766
|
)
|
1732
1767
|
if treeview and isinstance(self.MT._row_index, list) and len(self.MT._row_index) > datarn:
|
1733
1768
|
iid = self.MT._row_index[datarn].iid
|
1734
1769
|
max_width -= self.MT.index_txt_height
|
1735
|
-
if align
|
1770
|
+
if align[-1] == "w":
|
1736
1771
|
draw_x += self.MT.index_txt_height + 3
|
1737
1772
|
level, indent = self.get_iid_level_indent(iid)
|
1738
1773
|
draw_x += indent + 5
|
@@ -1741,7 +1776,6 @@ class RowIndex(tk.Canvas):
|
|
1741
1776
|
rtopgridln,
|
1742
1777
|
rbotgridln - 1,
|
1743
1778
|
fill=tree_arrow_fg,
|
1744
|
-
tag="ta",
|
1745
1779
|
indent=indent,
|
1746
1780
|
has_children=bool(self.MT._row_index[datarn].children),
|
1747
1781
|
open_=self.MT._row_index[datarn].iid in self.tree_open_ids,
|
@@ -1763,7 +1797,7 @@ class RowIndex(tk.Canvas):
|
|
1763
1797
|
wrap=wrap,
|
1764
1798
|
start_line=start_line,
|
1765
1799
|
)
|
1766
|
-
if align
|
1800
|
+
if align[-1] == "w" or align[-1] == "e":
|
1767
1801
|
if self.hidd_text:
|
1768
1802
|
iid, showing = self.hidd_text.popitem()
|
1769
1803
|
self.coords(iid, draw_x, draw_y)
|
@@ -1792,18 +1826,18 @@ class RowIndex(tk.Canvas):
|
|
1792
1826
|
fill=fill,
|
1793
1827
|
font=font,
|
1794
1828
|
anchor=align,
|
1795
|
-
|
1829
|
+
tag="lift",
|
1796
1830
|
)
|
1797
1831
|
self.disp_text[iid] = True
|
1798
1832
|
else:
|
1799
|
-
for
|
1833
|
+
for line in gen_lines:
|
1800
1834
|
if self.hidd_text:
|
1801
1835
|
iid, showing = self.hidd_text.popitem()
|
1802
1836
|
self.coords(iid, draw_x, draw_y)
|
1803
1837
|
if showing:
|
1804
1838
|
self.itemconfig(
|
1805
1839
|
iid,
|
1806
|
-
text=
|
1840
|
+
text=line,
|
1807
1841
|
fill=fill,
|
1808
1842
|
font=font,
|
1809
1843
|
anchor=align,
|
@@ -1811,7 +1845,7 @@ class RowIndex(tk.Canvas):
|
|
1811
1845
|
else:
|
1812
1846
|
self.itemconfig(
|
1813
1847
|
iid,
|
1814
|
-
text=
|
1848
|
+
text=line,
|
1815
1849
|
fill=fill,
|
1816
1850
|
font=font,
|
1817
1851
|
anchor=align,
|
@@ -1821,42 +1855,15 @@ class RowIndex(tk.Canvas):
|
|
1821
1855
|
iid = self.create_text(
|
1822
1856
|
draw_x,
|
1823
1857
|
draw_y,
|
1824
|
-
text=
|
1858
|
+
text=line,
|
1825
1859
|
fill=fill,
|
1826
1860
|
font=font,
|
1827
1861
|
anchor=align,
|
1828
|
-
|
1862
|
+
tag="lift",
|
1829
1863
|
)
|
1830
1864
|
self.disp_text[iid] = True
|
1831
1865
|
draw_y += self.MT.header_txt_height
|
1832
1866
|
|
1833
|
-
xend = self.current_width - 6
|
1834
|
-
if (self.ops.show_horizontal_grid or self.height_resizing_enabled) and row_pos_exists:
|
1835
|
-
points = [
|
1836
|
-
self.current_width - 1,
|
1837
|
-
y_stop - 1,
|
1838
|
-
self.current_width - 1,
|
1839
|
-
scrollpos_top - 1,
|
1840
|
-
-1,
|
1841
|
-
scrollpos_top - 1,
|
1842
|
-
]
|
1843
|
-
for r in range(grid_start_row, grid_end_row):
|
1844
|
-
draw_y = self.MT.row_positions[r]
|
1845
|
-
if r and self.height_resizing_enabled:
|
1846
|
-
self.visible_row_dividers[r] = (1, draw_y - 2, xend, draw_y + 2)
|
1847
|
-
points.extend(
|
1848
|
-
(
|
1849
|
-
-1,
|
1850
|
-
draw_y,
|
1851
|
-
self.current_width,
|
1852
|
-
draw_y,
|
1853
|
-
-1,
|
1854
|
-
draw_y,
|
1855
|
-
-1,
|
1856
|
-
self.MT.row_positions[r + 1] if len(self.MT.row_positions) - 1 > r else draw_y,
|
1857
|
-
)
|
1858
|
-
)
|
1859
|
-
self.redraw_gridline(points=points, fill=self.ops.index_grid_fg, width=1, tag="h")
|
1860
1867
|
for dct in (
|
1861
1868
|
self.hidd_text,
|
1862
1869
|
self.hidd_high,
|
@@ -1869,7 +1876,7 @@ class RowIndex(tk.Canvas):
|
|
1869
1876
|
if showing:
|
1870
1877
|
self.itemconfig(iid, state="hidden")
|
1871
1878
|
dct[iid] = False
|
1872
|
-
self.tag_raise("
|
1879
|
+
self.tag_raise("lift")
|
1873
1880
|
if self.disp_resize_lines:
|
1874
1881
|
self.tag_raise("rh")
|
1875
1882
|
return True
|
@@ -2729,16 +2736,17 @@ class RowIndex(tk.Canvas):
|
|
2729
2736
|
)
|
2730
2737
|
# deal with displayed mapping
|
2731
2738
|
event_data["moved"]["rows"]["displayed"] = {}
|
2732
|
-
|
2733
|
-
if
|
2734
|
-
if
|
2735
|
-
|
2739
|
+
with suppress(Exception):
|
2740
|
+
if new_loc_is_displayed:
|
2741
|
+
if disp_insert_row is None:
|
2742
|
+
if new_parent or insert_row > move_to_row:
|
2743
|
+
disp_insert_row = self.MT.disprn(self.rns[move_to_iid]) + 1
|
2744
|
+
else:
|
2745
|
+
disp_insert_row = self.MT.disprn(self.rns[move_to_iid])
|
2746
|
+
if (disp_from_row := self.MT.try_disprn(self.rns[item])) is not None:
|
2747
|
+
event_data["moved"]["rows"]["displayed"] = {disp_from_row: disp_insert_row}
|
2736
2748
|
else:
|
2737
|
-
|
2738
|
-
if (disp_from_row := self.MT.try_disprn(self.rns[item])) is not None:
|
2739
|
-
event_data["moved"]["rows"]["displayed"] = {disp_from_row: disp_insert_row}
|
2740
|
-
else:
|
2741
|
-
event_data["moved"]["rows"]["displayed"] = {(): disp_insert_row}
|
2749
|
+
event_data["moved"]["rows"]["displayed"] = {(): disp_insert_row}
|
2742
2750
|
|
2743
2751
|
if any(self.move_pid_causes_recursive_loop(self.MT._row_index[r].iid, new_parent) for r in moved_rows):
|
2744
2752
|
event_data["moved"]["rows"] = {}
|
@@ -2759,7 +2767,7 @@ class RowIndex(tk.Canvas):
|
|
2759
2767
|
event_data["moved"]["rows"]["data"],
|
2760
2768
|
)
|
2761
2769
|
data_new_idxs = event_data["moved"]["rows"]["data"]
|
2762
|
-
data_old_idxs =
|
2770
|
+
data_old_idxs = {v: k for k, v in data_new_idxs.items()}
|
2763
2771
|
|
2764
2772
|
if () in event_data["moved"]["rows"]["displayed"]:
|
2765
2773
|
del event_data["moved"]["rows"]["displayed"][()]
|
@@ -2988,15 +2996,6 @@ class RowIndex(tk.Canvas):
|
|
2988
2996
|
if not parent_node.children:
|
2989
2997
|
self.tree_open_ids.discard(parent_node.iid)
|
2990
2998
|
|
2991
|
-
def build_pid_causes_recursive_loop(self, iid: str, pid: str) -> bool:
|
2992
|
-
return any(
|
2993
|
-
i == pid
|
2994
|
-
for i in chain(
|
2995
|
-
self.get_iid_descendants(iid),
|
2996
|
-
islice(self.get_iid_ancestors(iid), 1, None),
|
2997
|
-
)
|
2998
|
-
)
|
2999
|
-
|
3000
2999
|
def move_pid_causes_recursive_loop(self, to_move_iid: str, move_to_parent: str) -> bool:
|
3001
3000
|
# if the parent the item is being moved under is one of the item's descendants
|
3002
3001
|
# then it is a recursive loop
|
@@ -3017,8 +3016,8 @@ class RowIndex(tk.Canvas):
|
|
3017
3016
|
include_parent_column: bool = True,
|
3018
3017
|
include_text_column: bool = True,
|
3019
3018
|
) -> None:
|
3020
|
-
index = self.MT._row_index
|
3021
3019
|
data_rns = {}
|
3020
|
+
tree = {}
|
3022
3021
|
if text_column is None:
|
3023
3022
|
text_column = iid_column
|
3024
3023
|
if not isinstance(ncols, int):
|
@@ -3030,33 +3029,27 @@ class RowIndex(tk.Canvas):
|
|
3030
3029
|
else:
|
3031
3030
|
iid = row[iid_column]
|
3032
3031
|
pid = row[parent_column]
|
3033
|
-
if iid in
|
3034
|
-
|
3032
|
+
if iid in tree:
|
3033
|
+
tree[iid].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
3035
3034
|
else:
|
3036
|
-
|
3037
|
-
|
3038
|
-
|
3039
|
-
|
3040
|
-
parent="",
|
3041
|
-
)
|
3035
|
+
tree[iid] = Node(
|
3036
|
+
text=row[text_column] if isinstance(text_column, int) else text_column[rn],
|
3037
|
+
iid=iid,
|
3038
|
+
parent="",
|
3042
3039
|
)
|
3043
|
-
self.rns[iid] = len(index) - 1
|
3044
3040
|
data_rns[iid] = rn
|
3045
3041
|
if pid:
|
3046
|
-
if pid in
|
3047
|
-
|
3042
|
+
if pid in tree:
|
3043
|
+
tree[pid].children.append(iid)
|
3048
3044
|
else:
|
3049
|
-
|
3050
|
-
|
3051
|
-
|
3052
|
-
|
3053
|
-
children=[iid],
|
3054
|
-
)
|
3045
|
+
tree[pid] = Node(
|
3046
|
+
text=pid,
|
3047
|
+
iid=pid,
|
3048
|
+
children=[iid],
|
3055
3049
|
)
|
3056
|
-
|
3057
|
-
index[self.rns[iid]].parent = pid
|
3050
|
+
tree[iid].parent = pid
|
3058
3051
|
else:
|
3059
|
-
|
3052
|
+
tree[iid].parent = ""
|
3060
3053
|
exclude = set()
|
3061
3054
|
if not include_iid_column:
|
3062
3055
|
exclude.add(iid_column)
|
@@ -3065,18 +3058,35 @@ class RowIndex(tk.Canvas):
|
|
3065
3058
|
if isinstance(text_column, int) and not include_text_column:
|
3066
3059
|
exclude.add(text_column)
|
3067
3060
|
rows = []
|
3061
|
+
ctr = 0
|
3068
3062
|
if exclude:
|
3069
|
-
for iid in
|
3070
|
-
|
3071
|
-
|
3072
|
-
|
3063
|
+
for iid, node in tree.items():
|
3064
|
+
if node.parent == "":
|
3065
|
+
row = [tree[iid]]
|
3066
|
+
row.extend(e for i, e in enumerate(data[data_rns[iid]]) if i not in exclude)
|
3067
|
+
rows.append(row)
|
3068
|
+
self.rns[iid] = ctr
|
3069
|
+
ctr += 1
|
3070
|
+
for diid in self._build_get_descendants(iid, tree):
|
3071
|
+
row = [tree[diid]]
|
3072
|
+
row.extend(e for i, e in enumerate(data[data_rns[diid]]) if i not in exclude)
|
3073
|
+
rows.append(row)
|
3074
|
+
self.rns[diid] = ctr
|
3075
|
+
ctr += 1
|
3073
3076
|
else:
|
3074
|
-
for iid in
|
3075
|
-
|
3076
|
-
|
3077
|
-
|
3078
|
-
|
3079
|
-
|
3077
|
+
for iid, node in tree.items():
|
3078
|
+
if node.parent == "":
|
3079
|
+
row = [tree[iid]]
|
3080
|
+
row.extend(data[data_rns[iid]])
|
3081
|
+
rows.append(row)
|
3082
|
+
self.rns[iid] = ctr
|
3083
|
+
ctr += 1
|
3084
|
+
for diid in self._build_get_descendants(iid, tree):
|
3085
|
+
row = [tree[diid]]
|
3086
|
+
row.extend(data[data_rns[diid]])
|
3087
|
+
rows.append(row)
|
3088
|
+
self.rns[diid] = ctr
|
3089
|
+
ctr += 1
|
3080
3090
|
self.PAR.insert_rows(
|
3081
3091
|
rows=rows,
|
3082
3092
|
idx=0,
|
@@ -3091,7 +3101,6 @@ class RowIndex(tk.Canvas):
|
|
3091
3101
|
)
|
3092
3102
|
self.MT.all_rows_displayed = False
|
3093
3103
|
self.MT.displayed_rows = list(range(len(self.MT._row_index)))
|
3094
|
-
self.rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
3095
3104
|
if open_ids:
|
3096
3105
|
self.PAR.tree_set_open(open_ids=open_ids)
|
3097
3106
|
else:
|
@@ -3118,8 +3127,8 @@ class RowIndex(tk.Canvas):
|
|
3118
3127
|
include_parent_column: bool = True,
|
3119
3128
|
include_text_column: bool = True,
|
3120
3129
|
) -> None:
|
3121
|
-
index = self.MT._row_index
|
3122
3130
|
data_rns = {}
|
3131
|
+
tree = {}
|
3123
3132
|
iids_missing_rows = set()
|
3124
3133
|
if text_column is None:
|
3125
3134
|
text_column = iid_column
|
@@ -3146,43 +3155,36 @@ class RowIndex(tk.Canvas):
|
|
3146
3155
|
x += 1
|
3147
3156
|
tally_of_ids[iid] += 1
|
3148
3157
|
row[iid_column] = new
|
3149
|
-
if iid in
|
3150
|
-
|
3158
|
+
if iid in tree:
|
3159
|
+
tree[iid].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
3151
3160
|
else:
|
3152
|
-
|
3153
|
-
|
3154
|
-
|
3155
|
-
|
3156
|
-
parent="",
|
3157
|
-
)
|
3161
|
+
tree[iid] = Node(
|
3162
|
+
text=row[text_column] if isinstance(text_column, int) else text_column[rn],
|
3163
|
+
iid=iid,
|
3164
|
+
parent="",
|
3158
3165
|
)
|
3159
|
-
self.rns[iid] = len(index) - 1
|
3160
3166
|
if iid in iids_missing_rows:
|
3161
3167
|
iids_missing_rows.discard(iid)
|
3162
3168
|
data_rns[iid] = rn
|
3163
|
-
if iid == pid or self.build_pid_causes_recursive_loop(iid, pid):
|
3169
|
+
if iid == pid or self.build_pid_causes_recursive_loop(iid, pid, tree):
|
3164
3170
|
row[parent_column] = ""
|
3165
3171
|
pid = ""
|
3166
3172
|
if pid:
|
3167
|
-
if pid in
|
3168
|
-
|
3173
|
+
if pid in tree:
|
3174
|
+
tree[pid].children.append(iid)
|
3169
3175
|
else:
|
3170
|
-
|
3171
|
-
|
3172
|
-
|
3173
|
-
|
3174
|
-
children=[iid],
|
3175
|
-
)
|
3176
|
+
tree[pid] = Node(
|
3177
|
+
text=pid,
|
3178
|
+
iid=pid,
|
3179
|
+
children=[iid],
|
3176
3180
|
)
|
3177
3181
|
iids_missing_rows.add(pid)
|
3178
|
-
|
3179
|
-
index[self.rns[iid]].parent = pid
|
3182
|
+
tree[iid].parent = pid
|
3180
3183
|
else:
|
3181
|
-
|
3184
|
+
tree[iid].parent = ""
|
3182
3185
|
empty_rows = {}
|
3183
3186
|
for iid in iids_missing_rows:
|
3184
|
-
node =
|
3185
|
-
node.parent = ""
|
3187
|
+
node = tree[iid]
|
3186
3188
|
newrow = self.MT.get_empty_row_seq(len(data), ncols)
|
3187
3189
|
newrow[iid_column] = node.iid
|
3188
3190
|
empty_rows[node.iid] = newrow
|
@@ -3194,24 +3196,41 @@ class RowIndex(tk.Canvas):
|
|
3194
3196
|
if isinstance(text_column, int) and not include_text_column:
|
3195
3197
|
exclude.add(text_column)
|
3196
3198
|
rows = []
|
3199
|
+
ctr = 0
|
3197
3200
|
if exclude:
|
3198
|
-
for iid in
|
3199
|
-
|
3200
|
-
|
3201
|
-
|
3202
|
-
|
3203
|
-
|
3204
|
-
|
3201
|
+
for iid, node in tree.items():
|
3202
|
+
if node.parent == "":
|
3203
|
+
row = [tree[iid]]
|
3204
|
+
if iid in empty_rows:
|
3205
|
+
row.extend(e for i, e in enumerate(empty_rows[iid]) if i not in exclude)
|
3206
|
+
else:
|
3207
|
+
row.extend(e for i, e in enumerate(data[data_rns[iid]]) if i not in exclude)
|
3208
|
+
rows.append(row)
|
3209
|
+
self.rns[iid] = ctr
|
3210
|
+
ctr += 1
|
3211
|
+
for diid in self._build_get_descendants(iid, tree):
|
3212
|
+
row = [tree[diid]]
|
3213
|
+
row.extend(e for i, e in enumerate(data[data_rns[diid]]) if i not in exclude)
|
3214
|
+
rows.append(row)
|
3215
|
+
self.rns[diid] = ctr
|
3216
|
+
ctr += 1
|
3205
3217
|
else:
|
3206
|
-
for iid in
|
3207
|
-
|
3208
|
-
|
3209
|
-
|
3210
|
-
|
3211
|
-
|
3212
|
-
|
3213
|
-
|
3214
|
-
|
3218
|
+
for iid, node in tree.items():
|
3219
|
+
if node.parent == "":
|
3220
|
+
row = [tree[iid]]
|
3221
|
+
if iid in empty_rows:
|
3222
|
+
row.extend(empty_rows[iid])
|
3223
|
+
else:
|
3224
|
+
row.extend(data[data_rns[iid]])
|
3225
|
+
rows.append(row)
|
3226
|
+
self.rns[iid] = ctr
|
3227
|
+
ctr += 1
|
3228
|
+
for diid in self._build_get_descendants(iid, tree):
|
3229
|
+
row = [tree[diid]]
|
3230
|
+
row.extend(data[data_rns[diid]])
|
3231
|
+
rows.append(row)
|
3232
|
+
self.rns[diid] = ctr
|
3233
|
+
ctr += 1
|
3215
3234
|
self.PAR.insert_rows(
|
3216
3235
|
rows=rows,
|
3217
3236
|
idx=0,
|
@@ -3226,7 +3245,6 @@ class RowIndex(tk.Canvas):
|
|
3226
3245
|
)
|
3227
3246
|
self.MT.all_rows_displayed = False
|
3228
3247
|
self.MT.displayed_rows = list(range(len(self.MT._row_index)))
|
3229
|
-
self.rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
3230
3248
|
if open_ids:
|
3231
3249
|
self.PAR.tree_set_open(open_ids=open_ids)
|
3232
3250
|
else:
|
@@ -3237,3 +3255,29 @@ class RowIndex(tk.Canvas):
|
|
3237
3255
|
data_indexes=True,
|
3238
3256
|
row_heights=row_heights is not False,
|
3239
3257
|
)
|
3258
|
+
|
3259
|
+
def _build_get_descendants(self, iid: str, tree: dict[str, Node]) -> Generator[str]:
|
3260
|
+
stack = [iter(tree[iid].children)]
|
3261
|
+
while stack:
|
3262
|
+
top_iterator = stack[-1]
|
3263
|
+
try:
|
3264
|
+
ciid = next(top_iterator)
|
3265
|
+
yield ciid
|
3266
|
+
if tree[ciid].children:
|
3267
|
+
stack.append(iter(tree[ciid].children))
|
3268
|
+
except StopIteration:
|
3269
|
+
stack.pop()
|
3270
|
+
|
3271
|
+
def build_pid_causes_recursive_loop(self, iid: str, pid: str, tree: dict[str, Node]) -> bool:
|
3272
|
+
# check descendants
|
3273
|
+
for diid in self._build_get_descendants(iid, tree):
|
3274
|
+
if diid == pid:
|
3275
|
+
return True
|
3276
|
+
# check ancestors
|
3277
|
+
current_iid = iid
|
3278
|
+
while tree[current_iid].parent:
|
3279
|
+
parent_iid = tree[current_iid].parent
|
3280
|
+
if parent_iid == pid:
|
3281
|
+
return True
|
3282
|
+
current_iid = parent_iid
|
3283
|
+
return False
|