tksheet 7.4.6__py3-none-any.whl → 7.4.7__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 +2 -1
- tksheet/functions.py +168 -266
- tksheet/main_table.py +55 -24
- tksheet/sheet.py +15 -8
- tksheet/sheet_options.py +3 -1
- {tksheet-7.4.6.dist-info → tksheet-7.4.7.dist-info}/METADATA +1 -1
- {tksheet-7.4.6.dist-info → tksheet-7.4.7.dist-info}/RECORD +10 -10
- {tksheet-7.4.6.dist-info → tksheet-7.4.7.dist-info}/WHEEL +1 -1
- {tksheet-7.4.6.dist-info → tksheet-7.4.7.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.4.6.dist-info → tksheet-7.4.7.dist-info}/top_level.txt +0 -0
tksheet/__init__.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
tksheet - A Python tkinter table widget
|
5
5
|
"""
|
6
6
|
|
7
|
-
__version__ = "7.4.
|
7
|
+
__version__ = "7.4.7"
|
8
8
|
|
9
9
|
from .colors import (
|
10
10
|
color_map,
|
@@ -73,6 +73,7 @@ from .functions import (
|
|
73
73
|
move_elements_to,
|
74
74
|
new_tk_event,
|
75
75
|
num2alpha,
|
76
|
+
push_n,
|
76
77
|
rounded_box_coords,
|
77
78
|
span_dict,
|
78
79
|
tksheet_type_error,
|
tksheet/functions.py
CHANGED
@@ -20,6 +20,7 @@ from .tksheet_types import AnyIter
|
|
20
20
|
|
21
21
|
unpickle_obj = pickle.loads
|
22
22
|
lines_re = re.compile(r"[^\n]+")
|
23
|
+
ORD_A = ord("A")
|
23
24
|
|
24
25
|
|
25
26
|
def wrap_text(
|
@@ -517,9 +518,8 @@ def force_bool(o: Any) -> bool:
|
|
517
518
|
def alpha2idx(a: str) -> int | None:
|
518
519
|
try:
|
519
520
|
n = 0
|
520
|
-
orda = ord("A")
|
521
521
|
for c in a.upper():
|
522
|
-
n = n * 26 + ord(c) -
|
522
|
+
n = n * 26 + ord(c) - ORD_A + 1
|
523
523
|
return n - 1
|
524
524
|
except Exception:
|
525
525
|
return None
|
@@ -1108,6 +1108,37 @@ def coords_to_span(
|
|
1108
1108
|
)
|
1109
1109
|
|
1110
1110
|
|
1111
|
+
PATTERN_ROW = re.compile(r"^(\d+)$") # "1"
|
1112
|
+
PATTERN_COL = re.compile(r"^([A-Z]+)$") # "A"
|
1113
|
+
PATTERN_CELL = re.compile(r"^([A-Z]+)(\d+)$") # "A1"
|
1114
|
+
PATTERN_RANGE = re.compile(r"^([A-Z]+)(\d+):([A-Z]+)(\d+)$") # "A1:B2"
|
1115
|
+
PATTERN_ROW_RANGE = re.compile(r"^(\d+):(\d+)$") # "1:2"
|
1116
|
+
PATTERN_ROW_START = re.compile(r"^(\d+):$") # "2:"
|
1117
|
+
PATTERN_ROW_END = re.compile(r"^:(\d+)$") # ":2"
|
1118
|
+
PATTERN_COL_RANGE = re.compile(r"^([A-Z]+):([A-Z]+)$") # "A:B"
|
1119
|
+
PATTERN_COL_START = re.compile(r"^([A-Z]+):$") # "A:"
|
1120
|
+
PATTERN_COL_END = re.compile(r"^:([A-Z]+)$") # ":B"
|
1121
|
+
PATTERN_CELL_START = re.compile(r"^([A-Z]+)(\d+):$") # "A1:"
|
1122
|
+
PATTERN_CELL_END = re.compile(r"^:([A-Z]+)(\d+)$") # ":B1"
|
1123
|
+
PATTERN_CELL_COL = re.compile(r"^([A-Z]+)(\d+):([A-Z]+)$") # "A1:B"
|
1124
|
+
PATTERN_CELL_ROW = re.compile(r"^([A-Z]+)(\d+):(\d+)$") # "A1:2"
|
1125
|
+
PATTERN_ALL = re.compile(r"^:$") # ":"
|
1126
|
+
|
1127
|
+
|
1128
|
+
def span_a2i(a: str) -> int | None:
|
1129
|
+
n = 0
|
1130
|
+
for c in a:
|
1131
|
+
n = n * 26 + ord(c) - ORD_A + 1
|
1132
|
+
return n - 1
|
1133
|
+
|
1134
|
+
|
1135
|
+
def span_a2n(a: str) -> int | None:
|
1136
|
+
n = 0
|
1137
|
+
for c in a:
|
1138
|
+
n = n * 26 + ord(c) - ORD_A + 1
|
1139
|
+
return n
|
1140
|
+
|
1141
|
+
|
1111
1142
|
def key_to_span(
|
1112
1143
|
key: (
|
1113
1144
|
str
|
@@ -1120,76 +1151,32 @@ def key_to_span(
|
|
1120
1151
|
spans: dict[str, Span],
|
1121
1152
|
widget: Any = None,
|
1122
1153
|
) -> Span:
|
1154
|
+
"""
|
1155
|
+
Convert various input types to a Span object representing a 2D range.
|
1156
|
+
|
1157
|
+
Args:
|
1158
|
+
key: The input to convert (str, int, slice, sequence, or None).
|
1159
|
+
spans: A dictionary of named spans (e.g., {"<name>": Span(...)}).
|
1160
|
+
widget: Optional widget context for span creation.
|
1161
|
+
|
1162
|
+
Returns:
|
1163
|
+
A Span object or an error message string if the key is invalid.
|
1164
|
+
"""
|
1165
|
+
# Handle Span object directly
|
1123
1166
|
if isinstance(key, Span):
|
1124
1167
|
return key
|
1168
|
+
|
1169
|
+
# Handle None as full span
|
1125
1170
|
elif key is None:
|
1126
|
-
|
1171
|
+
return coords_to_span(widget=widget, from_r=None, from_c=None, upto_r=None, upto_c=None)
|
1172
|
+
|
1173
|
+
# Validate input type
|
1127
1174
|
elif not isinstance(key, (str, int, slice, list, tuple)):
|
1128
|
-
return f"Key type must be either str, int, list, tuple or slice, not '{type(key)}'."
|
1175
|
+
return f"Key type must be either str, int, list, tuple or slice, not '{type(key).__name__}'."
|
1176
|
+
|
1129
1177
|
try:
|
1130
|
-
|
1131
|
-
|
1132
|
-
if len(key) == 2:
|
1133
|
-
"""
|
1134
|
-
(int | None, int | None) -
|
1135
|
-
(0, 0) - row 0, column 0 - the first cell
|
1136
|
-
(0, None) - row 0, all columns
|
1137
|
-
(None, 0) - column 0, all rows
|
1138
|
-
"""
|
1139
|
-
return span_dict(
|
1140
|
-
from_r=key[0] if isinstance(key[0], int) else 0,
|
1141
|
-
from_c=key[1] if isinstance(key[1], int) else 0,
|
1142
|
-
upto_r=(key[0] + 1) if isinstance(key[0], int) else None,
|
1143
|
-
upto_c=(key[1] + 1) if isinstance(key[1], int) else None,
|
1144
|
-
widget=widget,
|
1145
|
-
)
|
1146
|
-
|
1147
|
-
elif len(key) == 4:
|
1148
|
-
"""
|
1149
|
-
(int | None, int | None, int | None, int | None) -
|
1150
|
-
(from row, from column, up to row, up to column)
|
1151
|
-
"""
|
1152
|
-
return coords_to_span(
|
1153
|
-
widget=widget,
|
1154
|
-
from_r=key[0],
|
1155
|
-
from_c=key[1],
|
1156
|
-
upto_r=key[2],
|
1157
|
-
upto_c=key[3],
|
1158
|
-
)
|
1159
|
-
# return span_dict(
|
1160
|
-
# from_r=key[0] if isinstance(key[0], int) else 0,
|
1161
|
-
# from_c=key[1] if isinstance(key[1], int) else 0,
|
1162
|
-
# upto_r=key[2] if isinstance(key[2], int) else None,
|
1163
|
-
# upto_c=key[3] if isinstance(key[3], int) else None,
|
1164
|
-
# widget=widget,
|
1165
|
-
# )
|
1166
|
-
|
1167
|
-
elif isinstance(key[0], (list, tuple)):
|
1168
|
-
"""
|
1169
|
-
((int | None, int | None), (int | None, int | None))
|
1170
|
-
|
1171
|
-
First Sequence is start row and column
|
1172
|
-
Second Sequence is up to but not including row and column
|
1173
|
-
"""
|
1174
|
-
return coords_to_span(
|
1175
|
-
widget=widget,
|
1176
|
-
from_r=key[0][0],
|
1177
|
-
from_c=key[0][1],
|
1178
|
-
upto_r=key[1][0],
|
1179
|
-
upto_c=key[1][1],
|
1180
|
-
)
|
1181
|
-
# return span_dict(
|
1182
|
-
# from_r=key[0][0] if isinstance(key[0][0], int) else 0,
|
1183
|
-
# from_c=key[0][1] if isinstance(key[0][1], int) else 0,
|
1184
|
-
# upto_r=key[1][0],
|
1185
|
-
# upto_c=key[1][1],
|
1186
|
-
# widget=widget,
|
1187
|
-
# )
|
1188
|
-
|
1189
|
-
elif isinstance(key, int):
|
1190
|
-
"""
|
1191
|
-
[int] - Whole row at that index
|
1192
|
-
"""
|
1178
|
+
# Integer key: whole row
|
1179
|
+
if isinstance(key, int):
|
1193
1180
|
return span_dict(
|
1194
1181
|
from_r=key,
|
1195
1182
|
from_c=None,
|
@@ -1198,29 +1185,8 @@ def key_to_span(
|
|
1198
1185
|
widget=widget,
|
1199
1186
|
)
|
1200
1187
|
|
1188
|
+
# Slice key: row range
|
1201
1189
|
elif isinstance(key, slice):
|
1202
|
-
"""
|
1203
|
-
[slice]
|
1204
|
-
"""
|
1205
|
-
"""
|
1206
|
-
[:] - All rows
|
1207
|
-
"""
|
1208
|
-
if key.start is None and key.stop is None:
|
1209
|
-
"""
|
1210
|
-
[:]
|
1211
|
-
"""
|
1212
|
-
return span_dict(
|
1213
|
-
from_r=0,
|
1214
|
-
from_c=None,
|
1215
|
-
upto_r=None,
|
1216
|
-
upto_c=None,
|
1217
|
-
widget=widget,
|
1218
|
-
)
|
1219
|
-
"""
|
1220
|
-
[1:3] - Rows 1, 2
|
1221
|
-
[:2] - Rows up to but not including 2
|
1222
|
-
[2:] - Rows starting from and including 2
|
1223
|
-
"""
|
1224
1190
|
start = 0 if key.start is None else key.start
|
1225
1191
|
return span_dict(
|
1226
1192
|
from_r=start,
|
@@ -1230,251 +1196,187 @@ def key_to_span(
|
|
1230
1196
|
widget=widget,
|
1231
1197
|
)
|
1232
1198
|
|
1199
|
+
# Sequence key: various span formats
|
1200
|
+
elif isinstance(key, (list, tuple)):
|
1201
|
+
if (
|
1202
|
+
len(key) == 2
|
1203
|
+
and (isinstance(key[0], int) or key[0] is None)
|
1204
|
+
and (isinstance(key[1], int) or key[1] is None)
|
1205
|
+
):
|
1206
|
+
# Single cell or partial span: (row, col)
|
1207
|
+
r_int = isinstance(key[0], int)
|
1208
|
+
c_int = isinstance(key[1], int)
|
1209
|
+
return span_dict(
|
1210
|
+
from_r=key[0] if r_int else 0,
|
1211
|
+
from_c=key[1] if c_int else 0,
|
1212
|
+
upto_r=key[0] + 1 if r_int else None,
|
1213
|
+
upto_c=key[1] + 1 if c_int else None,
|
1214
|
+
widget=widget,
|
1215
|
+
)
|
1216
|
+
elif len(key) == 4:
|
1217
|
+
# Full span coordinates: (from_r, from_c, upto_r, upto_c)
|
1218
|
+
return coords_to_span(
|
1219
|
+
widget=widget,
|
1220
|
+
from_r=key[0],
|
1221
|
+
from_c=key[1],
|
1222
|
+
upto_r=key[2],
|
1223
|
+
upto_c=key[3],
|
1224
|
+
)
|
1225
|
+
elif len(key) == 2 and all(isinstance(k, (list, tuple)) for k in key):
|
1226
|
+
# Start and end points: ((from_r, from_c), (upto_r, upto_c))
|
1227
|
+
return coords_to_span(
|
1228
|
+
widget=widget,
|
1229
|
+
from_r=key[0][0],
|
1230
|
+
from_c=key[0][1],
|
1231
|
+
upto_r=key[1][0],
|
1232
|
+
upto_c=key[1][1],
|
1233
|
+
)
|
1234
|
+
|
1235
|
+
# String key: parse various span formats
|
1233
1236
|
elif isinstance(key, str):
|
1234
1237
|
if not key:
|
1235
|
-
|
1236
|
-
|
1237
|
-
if key.startswith("<") and key.endswith(">"):
|
1238
|
-
if (key := key[1:-1]) in spans:
|
1239
|
-
"""
|
1240
|
-
["<name>"] - Surrounded by "<" ">" cells from a named range
|
1241
|
-
"""
|
1242
|
-
return spans[key]
|
1243
|
-
return f"'{key}' not in named spans."
|
1244
|
-
|
1245
|
-
key = key.upper()
|
1246
|
-
|
1247
|
-
if key.isdigit():
|
1248
|
-
"""
|
1249
|
-
["1"] - Row 0
|
1250
|
-
"""
|
1238
|
+
# Empty string treated as full span
|
1251
1239
|
return span_dict(
|
1252
|
-
from_r=
|
1240
|
+
from_r=0,
|
1253
1241
|
from_c=None,
|
1254
|
-
upto_r=
|
1242
|
+
upto_r=None,
|
1255
1243
|
upto_c=None,
|
1256
1244
|
widget=widget,
|
1257
1245
|
)
|
1246
|
+
elif key.startswith("<") and key.endswith(">"):
|
1247
|
+
name = key[1:-1]
|
1248
|
+
return spans.get(name, f"'{name}' not in named spans.")
|
1258
1249
|
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1250
|
+
key = key.upper() # Case-insensitive parsing
|
1251
|
+
|
1252
|
+
# Match string against precompiled patterns
|
1253
|
+
if m := PATTERN_ROW.match(key):
|
1254
|
+
return span_dict(
|
1255
|
+
from_r=int(m[1]) - 1,
|
1256
|
+
from_c=None,
|
1257
|
+
upto_r=int(m[1]),
|
1258
|
+
upto_c=None,
|
1259
|
+
widget=widget,
|
1260
|
+
)
|
1261
|
+
elif m := PATTERN_COL.match(key):
|
1263
1262
|
return span_dict(
|
1264
1263
|
from_r=None,
|
1265
|
-
from_c=
|
1264
|
+
from_c=span_a2i(m[1]),
|
1266
1265
|
upto_r=None,
|
1267
|
-
upto_c=
|
1266
|
+
upto_c=span_a2n(m[1]),
|
1268
1267
|
widget=widget,
|
1269
1268
|
)
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
return f"'{key}' could not be converted to span."
|
1274
|
-
|
1275
|
-
if len(splitk) == 1 and not splitk[0].isdigit() and not splitk[0].isalpha() and not splitk[0][0].isdigit():
|
1276
|
-
"""
|
1277
|
-
["A1"] - Cell (0, 0)
|
1278
|
-
"""
|
1279
|
-
keys_digits = re.search(r"\d", splitk[0])
|
1280
|
-
if keys_digits:
|
1281
|
-
digits_start = keys_digits.start()
|
1282
|
-
if not digits_start:
|
1283
|
-
return f"'{key}' could not be converted to span."
|
1284
|
-
if digits_start:
|
1285
|
-
key_row = splitk[0][digits_start:]
|
1286
|
-
key_column = splitk[0][:digits_start]
|
1287
|
-
return span_dict(
|
1288
|
-
from_r=int(key_row) - 1,
|
1289
|
-
from_c=alpha2idx(key_column),
|
1290
|
-
upto_r=int(key_row),
|
1291
|
-
upto_c=alpha2idx(key_column) + 1,
|
1292
|
-
widget=widget,
|
1293
|
-
)
|
1294
|
-
|
1295
|
-
if not splitk[0] and not splitk[1]:
|
1296
|
-
"""
|
1297
|
-
[":"] - All rows
|
1298
|
-
"""
|
1269
|
+
elif m := PATTERN_CELL.match(key):
|
1270
|
+
c = span_a2i(m[1])
|
1271
|
+
r = int(m[2]) - 1
|
1299
1272
|
return span_dict(
|
1300
|
-
from_r=
|
1301
|
-
from_c=
|
1302
|
-
upto_r=
|
1303
|
-
upto_c=
|
1273
|
+
from_r=r,
|
1274
|
+
from_c=c,
|
1275
|
+
upto_r=r + 1,
|
1276
|
+
upto_c=c + 1,
|
1304
1277
|
widget=widget,
|
1305
1278
|
)
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1279
|
+
elif m := PATTERN_RANGE.match(key):
|
1280
|
+
return span_dict(
|
1281
|
+
from_r=int(m[2]) - 1,
|
1282
|
+
from_c=span_a2i(m[1]),
|
1283
|
+
upto_r=int(m[4]),
|
1284
|
+
upto_c=span_a2n(m[3]),
|
1285
|
+
widget=widget,
|
1286
|
+
)
|
1287
|
+
elif m := PATTERN_ROW_RANGE.match(key):
|
1311
1288
|
return span_dict(
|
1312
|
-
from_r=int(
|
1289
|
+
from_r=int(m[1]) - 1,
|
1313
1290
|
from_c=None,
|
1314
|
-
upto_r=
|
1291
|
+
upto_r=int(m[2]),
|
1315
1292
|
upto_c=None,
|
1316
1293
|
widget=widget,
|
1317
1294
|
)
|
1318
|
-
|
1319
|
-
if splitk[1].isdigit() and not splitk[0]:
|
1320
|
-
"""
|
1321
|
-
[":2"] - Rows up to and including 1
|
1322
|
-
"""
|
1295
|
+
elif m := PATTERN_ROW_START.match(key):
|
1323
1296
|
return span_dict(
|
1324
|
-
from_r=
|
1297
|
+
from_r=int(m[1]) - 1,
|
1325
1298
|
from_c=None,
|
1326
|
-
upto_r=
|
1299
|
+
upto_r=None,
|
1327
1300
|
upto_c=None,
|
1328
1301
|
widget=widget,
|
1329
1302
|
)
|
1330
|
-
|
1331
|
-
if splitk[0].isdigit() and splitk[1].isdigit():
|
1332
|
-
"""
|
1333
|
-
["1:2"] - Rows 0, 1
|
1334
|
-
"""
|
1303
|
+
elif m := PATTERN_ROW_END.match(key):
|
1335
1304
|
return span_dict(
|
1336
|
-
from_r=
|
1305
|
+
from_r=0,
|
1337
1306
|
from_c=None,
|
1338
|
-
upto_r=int(
|
1307
|
+
upto_r=int(m[1]),
|
1339
1308
|
upto_c=None,
|
1340
1309
|
widget=widget,
|
1341
1310
|
)
|
1342
|
-
|
1343
|
-
if splitk[0].isalpha() and not splitk[1]:
|
1344
|
-
"""
|
1345
|
-
["B:"] - Columns starting from and including 2
|
1346
|
-
"""
|
1311
|
+
elif m := PATTERN_COL_RANGE.match(key):
|
1347
1312
|
return span_dict(
|
1348
1313
|
from_r=None,
|
1349
|
-
from_c=
|
1314
|
+
from_c=span_a2i(m[1]),
|
1350
1315
|
upto_r=None,
|
1351
|
-
upto_c=
|
1316
|
+
upto_c=span_a2n(m[2]),
|
1352
1317
|
widget=widget,
|
1353
1318
|
)
|
1354
|
-
|
1355
|
-
if splitk[1].isalpha() and not splitk[0]:
|
1356
|
-
"""
|
1357
|
-
[":B"] - Columns up to and including 2
|
1358
|
-
"""
|
1319
|
+
elif m := PATTERN_COL_START.match(key):
|
1359
1320
|
return span_dict(
|
1360
1321
|
from_r=None,
|
1361
|
-
from_c=
|
1322
|
+
from_c=span_a2i(m[1]),
|
1362
1323
|
upto_r=None,
|
1363
|
-
upto_c=
|
1324
|
+
upto_c=None,
|
1364
1325
|
widget=widget,
|
1365
1326
|
)
|
1366
|
-
|
1367
|
-
if splitk[0].isalpha() and splitk[1].isalpha():
|
1368
|
-
"""
|
1369
|
-
["A:B"] - Columns 0, 1
|
1370
|
-
"""
|
1327
|
+
elif m := PATTERN_COL_END.match(key):
|
1371
1328
|
return span_dict(
|
1372
1329
|
from_r=None,
|
1373
|
-
from_c=
|
1330
|
+
from_c=0,
|
1374
1331
|
upto_r=None,
|
1375
|
-
upto_c=
|
1332
|
+
upto_c=span_a2n(m[1]),
|
1376
1333
|
widget=widget,
|
1377
1334
|
)
|
1378
|
-
|
1379
|
-
m1 = re.search(r"\d", splitk[0])
|
1380
|
-
m2 = re.search(r"\d", splitk[1])
|
1381
|
-
m1start = m1.start() if m1 else None
|
1382
|
-
m2start = m2.start() if m2 else None
|
1383
|
-
if m1start and m2start:
|
1384
|
-
"""
|
1385
|
-
["A1:B1"] - Cells (0, 0), (0, 1)
|
1386
|
-
"""
|
1387
|
-
c1 = splitk[0][:m1start]
|
1388
|
-
r1 = splitk[0][m1start:]
|
1389
|
-
c2 = splitk[1][:m2start]
|
1390
|
-
r2 = splitk[1][m2start:]
|
1335
|
+
elif m := PATTERN_CELL_START.match(key):
|
1391
1336
|
return span_dict(
|
1392
|
-
from_r=int(
|
1393
|
-
from_c=
|
1394
|
-
upto_r=
|
1395
|
-
upto_c=
|
1337
|
+
from_r=int(m[2]) - 1,
|
1338
|
+
from_c=span_a2i(m[1]),
|
1339
|
+
upto_r=None,
|
1340
|
+
upto_c=None,
|
1396
1341
|
widget=widget,
|
1397
1342
|
)
|
1398
|
-
|
1399
|
-
if not splitk[0] and m2start:
|
1400
|
-
"""
|
1401
|
-
[":B1"] - Cells (0, 0), (0, 1)
|
1402
|
-
"""
|
1403
|
-
c2 = splitk[1][:m2start]
|
1404
|
-
r2 = splitk[1][m2start:]
|
1343
|
+
elif m := PATTERN_CELL_END.match(key):
|
1405
1344
|
return span_dict(
|
1406
1345
|
from_r=0,
|
1407
1346
|
from_c=0,
|
1408
|
-
upto_r=int(
|
1409
|
-
upto_c=
|
1347
|
+
upto_r=int(m[2]),
|
1348
|
+
upto_c=span_a2n(m[1]),
|
1410
1349
|
widget=widget,
|
1411
1350
|
)
|
1412
|
-
|
1413
|
-
if not splitk[1] and m1start:
|
1414
|
-
"""
|
1415
|
-
["A1:"] - Cells starting from and including (0, 0)
|
1416
|
-
"""
|
1417
|
-
c1 = splitk[0][:m1start]
|
1418
|
-
r1 = splitk[0][m1start:]
|
1351
|
+
elif m := PATTERN_CELL_COL.match(key):
|
1419
1352
|
return span_dict(
|
1420
|
-
from_r=int(
|
1421
|
-
from_c=
|
1353
|
+
from_r=int(m[2]) - 1,
|
1354
|
+
from_c=span_a2i(m[1]),
|
1422
1355
|
upto_r=None,
|
1423
|
-
upto_c=
|
1356
|
+
upto_c=span_a2n(m[3]),
|
1424
1357
|
widget=widget,
|
1425
1358
|
)
|
1426
|
-
|
1427
|
-
if m1start and splitk[1].isalpha():
|
1428
|
-
"""
|
1429
|
-
["A1:B"] - All the cells starting from (0, 0)
|
1430
|
-
expanding out to include column 1
|
1431
|
-
but not including cells beyond column
|
1432
|
-
1 and expanding down to include all rows
|
1433
|
-
A B C D
|
1434
|
-
1 x x
|
1435
|
-
2 x x
|
1436
|
-
3 x x
|
1437
|
-
4 x x
|
1438
|
-
...
|
1439
|
-
"""
|
1440
|
-
c1 = splitk[0][:m1start]
|
1441
|
-
r1 = splitk[0][m1start:]
|
1359
|
+
elif m := PATTERN_CELL_ROW.match(key):
|
1442
1360
|
return span_dict(
|
1443
|
-
from_r=int(
|
1444
|
-
from_c=
|
1445
|
-
upto_r=
|
1446
|
-
upto_c=
|
1361
|
+
from_r=int(m[2]) - 1,
|
1362
|
+
from_c=span_a2i(m[1]),
|
1363
|
+
upto_r=int(m[3]),
|
1364
|
+
upto_c=None,
|
1447
1365
|
widget=widget,
|
1448
1366
|
)
|
1449
|
-
|
1450
|
-
if m1start and splitk[1].isdigit():
|
1451
|
-
"""
|
1452
|
-
["A1:2"] - All the cells starting from (0, 0)
|
1453
|
-
expanding down to include row 1
|
1454
|
-
but not including cells beyond row
|
1455
|
-
1 and expanding out to include all
|
1456
|
-
columns
|
1457
|
-
A B C D
|
1458
|
-
1 x x x x
|
1459
|
-
2 x x x x
|
1460
|
-
3
|
1461
|
-
4
|
1462
|
-
...
|
1463
|
-
"""
|
1464
|
-
c1 = splitk[0][:m1start]
|
1465
|
-
r1 = splitk[0][m1start:]
|
1367
|
+
elif PATTERN_ALL.match(key):
|
1466
1368
|
return span_dict(
|
1467
|
-
from_r=
|
1468
|
-
from_c=
|
1469
|
-
upto_r=
|
1369
|
+
from_r=0,
|
1370
|
+
from_c=None,
|
1371
|
+
upto_r=None,
|
1470
1372
|
upto_c=None,
|
1471
1373
|
widget=widget,
|
1472
1374
|
)
|
1375
|
+
else:
|
1376
|
+
return f"'{key}' could not be converted to span."
|
1473
1377
|
|
1474
1378
|
except ValueError as error:
|
1475
1379
|
return f"Error, '{key}' could not be converted to span: {error}"
|
1476
|
-
else:
|
1477
|
-
return f"'{key}' could not be converted to span."
|
1478
1380
|
|
1479
1381
|
|
1480
1382
|
def span_is_cell(span: Span) -> bool:
|
tksheet/main_table.py
CHANGED
@@ -555,16 +555,31 @@ class MainTable(tk.Canvas):
|
|
555
555
|
return coords
|
556
556
|
|
557
557
|
def find_match(self, find: str, r: int, c: int) -> bool:
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
558
|
+
try:
|
559
|
+
value = self.data[r][c]
|
560
|
+
except Exception:
|
561
|
+
value = ""
|
562
|
+
kwargs = self.get_cell_kwargs(r, c, key=None)
|
563
|
+
if kwargs:
|
564
|
+
if "dropdown" in kwargs:
|
565
|
+
kwargs = kwargs["dropdown"]
|
566
|
+
if kwargs["text"] is not None and find in str(kwargs["text"]).lower():
|
567
|
+
return True
|
568
|
+
elif "checkbox" in kwargs:
|
569
|
+
kwargs = kwargs["checkbox"]
|
570
|
+
if find in str(kwargs["text"]).lower() or (not find and find in "False"):
|
571
|
+
return True
|
572
|
+
elif "format" in kwargs:
|
573
|
+
if kwargs["formatter"] is None:
|
574
|
+
if find in data_to_str(value, **kwargs).lower():
|
575
|
+
return True
|
576
|
+
# assumed given formatter class has __str__() or value attribute
|
577
|
+
elif find in str(value).lower() or find in str(value.value).lower():
|
578
|
+
return True
|
579
|
+
if value is None:
|
580
|
+
return find == ""
|
581
|
+
else:
|
582
|
+
return find in str(value).lower()
|
568
583
|
|
569
584
|
def find_within_match(self, find: str, r: int, c: int) -> bool:
|
570
585
|
if not self.all_rows_displayed:
|
@@ -669,9 +684,9 @@ class MainTable(tk.Canvas):
|
|
669
684
|
reverse=reverse,
|
670
685
|
)
|
671
686
|
if (
|
672
|
-
|
687
|
+
self.find_match(find, r, c)
|
688
|
+
and (self.all_rows_displayed or bisect_in(self.displayed_rows, r))
|
673
689
|
and (self.all_columns_displayed or bisect_in(self.displayed_columns, c))
|
674
|
-
and self.find_match(find, r, c)
|
675
690
|
)
|
676
691
|
),
|
677
692
|
None,
|
@@ -2039,8 +2054,10 @@ class MainTable(tk.Canvas):
|
|
2039
2054
|
redraw: bool = True,
|
2040
2055
|
r_pc: float = 0.0,
|
2041
2056
|
c_pc: float = 0.0,
|
2057
|
+
index: bool = True,
|
2042
2058
|
) -> bool:
|
2043
|
-
|
2059
|
+
need_y_redraw = False
|
2060
|
+
need_x_redraw = False
|
2044
2061
|
vis_info = self.cell_visibility_info(r, c)
|
2045
2062
|
yvis, xvis = vis_info["yvis"], vis_info["xvis"]
|
2046
2063
|
top_left_x, top_left_y, bottom_right_x, bottom_right_y = vis_info["visible_region"]
|
@@ -2067,7 +2084,7 @@ class MainTable(tk.Canvas):
|
|
2067
2084
|
y - 1 if y > 1 else y,
|
2068
2085
|
]
|
2069
2086
|
self.set_yviews(*args, redraw=False)
|
2070
|
-
|
2087
|
+
need_y_redraw = True
|
2071
2088
|
else:
|
2072
2089
|
if r is not None and not keep_yscroll:
|
2073
2090
|
y = max(
|
@@ -2079,7 +2096,7 @@ class MainTable(tk.Canvas):
|
|
2079
2096
|
y - 1 if y > 1 else y,
|
2080
2097
|
]
|
2081
2098
|
self.set_yviews(*args, redraw=False)
|
2082
|
-
|
2099
|
+
need_y_redraw = True
|
2083
2100
|
# x scroll
|
2084
2101
|
if not check_cell_visibility or (check_cell_visibility and not xvis) and len(self.col_positions) > 1:
|
2085
2102
|
if bottom_right_corner is None:
|
@@ -2102,7 +2119,7 @@ class MainTable(tk.Canvas):
|
|
2102
2119
|
x - 1 if x > 1 else x,
|
2103
2120
|
]
|
2104
2121
|
self.set_xviews(*args, redraw=False)
|
2105
|
-
|
2122
|
+
need_x_redraw = True
|
2106
2123
|
else:
|
2107
2124
|
if c is not None and not keep_xscroll:
|
2108
2125
|
x = max(
|
@@ -2114,8 +2131,22 @@ class MainTable(tk.Canvas):
|
|
2114
2131
|
x - 1 if x > 1 else x,
|
2115
2132
|
]
|
2116
2133
|
self.set_xviews(*args, redraw=False)
|
2117
|
-
|
2118
|
-
|
2134
|
+
need_x_redraw = True
|
2135
|
+
# the index may have resized after scrolling making x calculation wrong
|
2136
|
+
if need_x_redraw and index and self.PAR.ops.auto_resize_row_index and self.show_index:
|
2137
|
+
self.main_table_redraw_grid_and_text(redraw_header=False, redraw_row_index=False, redraw_table=False)
|
2138
|
+
self.see(
|
2139
|
+
r=r,
|
2140
|
+
c=c,
|
2141
|
+
keep_yscroll=keep_yscroll,
|
2142
|
+
keep_xscroll=keep_xscroll,
|
2143
|
+
check_cell_visibility=check_cell_visibility,
|
2144
|
+
redraw=redraw,
|
2145
|
+
r_pc=r_pc,
|
2146
|
+
c_pc=c_pc,
|
2147
|
+
index=False,
|
2148
|
+
)
|
2149
|
+
if redraw and (need_y_redraw or need_x_redraw):
|
2119
2150
|
self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
|
2120
2151
|
return True
|
2121
2152
|
return False
|
@@ -2534,7 +2565,7 @@ class MainTable(tk.Canvas):
|
|
2534
2565
|
):
|
2535
2566
|
self.select_cell(r - 1, c, redraw=True)
|
2536
2567
|
|
2537
|
-
def arrowkey_LEFT(self, event: Any = None) ->
|
2568
|
+
def arrowkey_LEFT(self, event: Any = None) -> Literal["break"]:
|
2538
2569
|
if not self.selected:
|
2539
2570
|
return
|
2540
2571
|
r = self.selected.row
|
@@ -2550,6 +2581,7 @@ class MainTable(tk.Canvas):
|
|
2550
2581
|
self.single_selection_enabled or self.toggle_selection_enabled
|
2551
2582
|
):
|
2552
2583
|
self.select_cell(r, c - 1, redraw=True)
|
2584
|
+
return "break"
|
2553
2585
|
|
2554
2586
|
def arrowkey_DOWN(self, event: Any = None) -> None:
|
2555
2587
|
if not self.selected:
|
@@ -5572,8 +5604,7 @@ class MainTable(tk.Canvas):
|
|
5572
5604
|
|
5573
5605
|
def total_data_cols(self, include_header: bool = True) -> int:
|
5574
5606
|
h_total = len(self._headers) if include_header and isinstance(self._headers, (list, tuple)) else 0
|
5575
|
-
|
5576
|
-
d_total = max(map(len, self.data), default=0)
|
5607
|
+
d_total = max(map(len, self.data), default=0) # max(map(len, )) is faster
|
5577
5608
|
return max(h_total, d_total)
|
5578
5609
|
|
5579
5610
|
def total_data_rows(self, include_index: bool = True) -> int:
|
@@ -6115,7 +6146,7 @@ class MainTable(tk.Canvas):
|
|
6115
6146
|
|
6116
6147
|
# check if auto resizing row index
|
6117
6148
|
changed_w = False
|
6118
|
-
if self.PAR.ops.auto_resize_row_index and
|
6149
|
+
if self.PAR.ops.auto_resize_row_index and self.show_index:
|
6119
6150
|
changed_w = self.RI.auto_set_index_width(
|
6120
6151
|
end_row=grid_end_row,
|
6121
6152
|
only_rows=map(self.datarn, range(text_start_row, text_end_row)),
|
@@ -7653,12 +7684,12 @@ class MainTable(tk.Canvas):
|
|
7653
7684
|
self.focus_set()
|
7654
7685
|
return closed_dd_coords
|
7655
7686
|
|
7656
|
-
def mouseclick_outside_editor_or_dropdown_all_canvases(self):
|
7687
|
+
def mouseclick_outside_editor_or_dropdown_all_canvases(self) -> tuple[int, int] | None:
|
7657
7688
|
self.CH.mouseclick_outside_editor_or_dropdown()
|
7658
7689
|
self.RI.mouseclick_outside_editor_or_dropdown()
|
7659
7690
|
return self.mouseclick_outside_editor_or_dropdown()
|
7660
7691
|
|
7661
|
-
def hide_dropdown_editor_all_canvases(self):
|
7692
|
+
def hide_dropdown_editor_all_canvases(self) -> None:
|
7662
7693
|
self.hide_text_editor_and_dropdown(redraw=False)
|
7663
7694
|
self.RI.hide_text_editor_and_dropdown(redraw=False)
|
7664
7695
|
self.CH.hide_text_editor_and_dropdown(redraw=False)
|
tksheet/sheet.py
CHANGED
@@ -5238,14 +5238,6 @@ class Sheet(tk.Frame):
|
|
5238
5238
|
"""
|
5239
5239
|
if item not in self.RI.tree:
|
5240
5240
|
raise ValueError(f"Item '{item}' does not exist.")
|
5241
|
-
if isinstance(iid, str):
|
5242
|
-
if iid in self.RI.tree:
|
5243
|
-
raise ValueError(f"Cannot rename '{iid}', it already exists.")
|
5244
|
-
self.RI.tree[item].iid = iid
|
5245
|
-
self.RI.tree[iid] = self.RI.tree.pop(item)
|
5246
|
-
self.RI.tree_rns[iid] = self.RI.tree_rns.pop(item)
|
5247
|
-
if iid in self.RI.tree_open_ids:
|
5248
|
-
self.RI.tree_open_ids[iid] = self.RI.tree_open_ids.pop(item)
|
5249
5241
|
if isinstance(text, str):
|
5250
5242
|
self.RI.tree[item].text = text
|
5251
5243
|
if isinstance(values, list):
|
@@ -5273,6 +5265,21 @@ class Sheet(tk.Frame):
|
|
5273
5265
|
)
|
5274
5266
|
else:
|
5275
5267
|
self.RI.tree_open_ids.discard(item)
|
5268
|
+
if isinstance(iid, str):
|
5269
|
+
if iid in self.RI.tree:
|
5270
|
+
raise ValueError(f"Cannot rename '{iid}', it already exists.")
|
5271
|
+
for ciid in self.RI.tree[item].children:
|
5272
|
+
self.RI.tree[ciid].parent = iid
|
5273
|
+
if self.RI.tree[item].parent:
|
5274
|
+
parent_node = self.RI.parent_node(item)
|
5275
|
+
item_index = parent_node.children.index(item)
|
5276
|
+
parent_node.children[item_index] = iid
|
5277
|
+
self.RI.tree[item].iid = iid
|
5278
|
+
self.RI.tree[iid] = self.RI.tree.pop(item)
|
5279
|
+
self.RI.tree_rns[iid] = self.RI.tree_rns.pop(item)
|
5280
|
+
if item in self.RI.tree_open_ids:
|
5281
|
+
self.RI.tree_open_ids.discard(item)
|
5282
|
+
self.RI.tree_open_ids.add(iid)
|
5276
5283
|
get = not (isinstance(iid, str) or isinstance(text, str) or isinstance(values, list) or isinstance(open_, bool))
|
5277
5284
|
self.set_refresh_timer(redraw=not get and redraw)
|
5278
5285
|
if get:
|
tksheet/sheet_options.py
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
tksheet/__init__.py,sha256=
|
1
|
+
tksheet/__init__.py,sha256=EmUtHKfAbTqVrw9CsNFKo9Mwpptg16G8g25xCMl8qQU,2326
|
2
2
|
tksheet/colors.py,sha256=dHhmdFuQDlwohDHsAfT9VdrKoSl_R33L72a3HCin5zo,51591
|
3
3
|
tksheet/column_headers.py,sha256=uz3eRsJcKVj0fJd-cGrwXV1rA06asPENJvAibSGlHTM,103164
|
4
4
|
tksheet/constants.py,sha256=P2Bu4xzF82GGgZtoREdG-wBOyWOlY-2Pyvg_SNYXE6k,3941
|
5
5
|
tksheet/find_window.py,sha256=PNSQweZ2advYCfSYm4gWM7BQ8NaiwD822eiIZpSTyrw,8020
|
6
6
|
tksheet/formatters.py,sha256=DGcRiMsDJnySNpQcjfiX84oJ7TmOSMdU6u9injIhA4g,10095
|
7
|
-
tksheet/functions.py,sha256=
|
8
|
-
tksheet/main_table.py,sha256=
|
7
|
+
tksheet/functions.py,sha256=oMRhkihBHggRDwvP8arxeaPJZEML3WFs2d21y2tb_e4,49380
|
8
|
+
tksheet/main_table.py,sha256=tckEcddyVfvpJ7ceAilwIWlNrO3nQNbHYeJJ1fiq-aA,355818
|
9
9
|
tksheet/other_classes.py,sha256=pe9_Cj6d3rdeMif9nGvUz0MEUChf0l4d669RNqcNhY4,16578
|
10
10
|
tksheet/row_index.py,sha256=BJW7_Bvk6ozyy-88ML9JmUwmR5tko7dWAINO6YwrkrA,134210
|
11
|
-
tksheet/sheet.py,sha256=
|
12
|
-
tksheet/sheet_options.py,sha256=
|
11
|
+
tksheet/sheet.py,sha256=T1KvV3uiBpLqFF3SPCctBKN_CW3k1NWia_mg5EMDZ1M,284039
|
12
|
+
tksheet/sheet_options.py,sha256=amTUYpOg_Nf7C4t50-GG5sJuGeNWe_qOk8xWh2OwgfY,9818
|
13
13
|
tksheet/sorting.py,sha256=-x1ZBIYfaneRrQPhbb0Ehs70373o52ADXp481La3nOY,16806
|
14
14
|
tksheet/text_editor.py,sha256=rU8Fz0-ltkM63W9io2DoZJPyzUGzCc9Z0qBtc4D1H40,7404
|
15
15
|
tksheet/themes.py,sha256=AoNAxibnQi04MN0Zpbn9-kyDnkiiV8TDNWP9FYjpuf0,18473
|
16
16
|
tksheet/tksheet_types.py,sha256=8i3BlJrqCO9d4HD-XYl_mSSHQAeAzrRKRXneS6ZzorM,4624
|
17
17
|
tksheet/top_left_rectangle.py,sha256=M52IrPIeMoYE3jSpooZmqw_0W5Fz_R-Yu1ZqA685EZ8,8557
|
18
|
-
tksheet-7.4.
|
19
|
-
tksheet-7.4.
|
20
|
-
tksheet-7.4.
|
21
|
-
tksheet-7.4.
|
22
|
-
tksheet-7.4.
|
18
|
+
tksheet-7.4.7.dist-info/LICENSE.txt,sha256=ndbcCPe9SlHfweE_W2RAueWUe2k7yudyxYLq6WjFdn4,1101
|
19
|
+
tksheet-7.4.7.dist-info/METADATA,sha256=zETY1GL5-ES-qTVmM1EAcMxmWAAi2Po-XNuZjLMWD4g,8005
|
20
|
+
tksheet-7.4.7.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
21
|
+
tksheet-7.4.7.dist-info/top_level.txt,sha256=my61PXCcck_HHAc9cq3NAlyAr3A3FXxCy9gptEOaCN8,8
|
22
|
+
tksheet-7.4.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|