tksheet 7.2.21__tar.gz → 7.2.23__tar.gz
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-7.2.21/tksheet.egg-info → tksheet-7.2.23}/PKG-INFO +2 -2
- {tksheet-7.2.21 → tksheet-7.2.23}/README.md +1 -1
- {tksheet-7.2.21 → tksheet-7.2.23}/pyproject.toml +1 -1
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/__init__.py +1 -1
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/column_headers.py +75 -64
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/functions.py +31 -4
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/main_table.py +182 -120
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/other_classes.py +21 -1
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/row_index.py +68 -64
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/sheet.py +170 -23
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/sheet_options.py +1 -72
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/text_editor.py +11 -0
- tksheet-7.2.23/tksheet/themes.py +412 -0
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/vars.py +4 -1
- {tksheet-7.2.21 → tksheet-7.2.23/tksheet.egg-info}/PKG-INFO +2 -2
- tksheet-7.2.21/tksheet/themes.py +0 -342
- {tksheet-7.2.21 → tksheet-7.2.23}/LICENSE.txt +0 -0
- {tksheet-7.2.21 → tksheet-7.2.23}/setup.cfg +0 -0
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/colors.py +0 -0
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/formatters.py +0 -0
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/top_left_rectangle.py +0 -0
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/types.py +0 -0
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet.egg-info/SOURCES.txt +0 -0
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet.egg-info/dependency_links.txt +0 -0
- {tksheet-7.2.21 → tksheet-7.2.23}/tksheet.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: tksheet
|
3
|
-
Version: 7.2.
|
3
|
+
Version: 7.2.23
|
4
4
|
Summary: Tkinter table / sheet widget
|
5
5
|
Author-email: ragardner <github@ragardner.simplelogin.com>
|
6
6
|
License: Copyright (c) 2019 ragardner and open source contributors
|
@@ -46,7 +46,7 @@ License-File: LICENSE.txt
|
|
46
46
|
|
47
47
|
# <div align="center">tksheet - python tkinter table widget</div>
|
48
48
|
|
49
|
-
[](https://pypi.python.org/pypi/tksheet/)  [](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
|
49
|
+
[](https://pypi.python.org/pypi/tksheet/)  [](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
|
50
50
|
|
51
51
|
[](https://github.com/ragardner/tksheet/releases) [](https://pypi.org/project/tksheet/)
|
52
52
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
# <div align="center">tksheet - python tkinter table widget</div>
|
6
6
|
|
7
|
-
[](https://pypi.python.org/pypi/tksheet/)  [](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
|
7
|
+
[](https://pypi.python.org/pypi/tksheet/)  [](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
|
8
8
|
|
9
9
|
[](https://github.com/ragardner/tksheet/releases) [](https://pypi.org/project/tksheet/)
|
10
10
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
6
6
|
name = "tksheet"
|
7
7
|
description = "Tkinter table / sheet widget"
|
8
8
|
readme = "README.md"
|
9
|
-
version = "7.2.
|
9
|
+
version = "7.2.23"
|
10
10
|
authors = [{ name = "ragardner", email = "github@ragardner.simplelogin.com" }]
|
11
11
|
requires-python = ">=3.8"
|
12
12
|
license = {file = "LICENSE.txt"}
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
3
3
|
import tkinter as tk
|
4
4
|
from collections import defaultdict
|
5
5
|
from collections.abc import (
|
6
|
-
Callable,
|
7
6
|
Hashable,
|
8
7
|
Sequence,
|
9
8
|
)
|
@@ -805,19 +804,17 @@ class ColumnHeaders(tk.Canvas):
|
|
805
804
|
)
|
806
805
|
|
807
806
|
def b1_release(self, event: object) -> None:
|
807
|
+
to_hide = self.being_drawn_item
|
808
808
|
if self.being_drawn_item is not None and (to_sel := self.MT.coords_and_type(self.being_drawn_item)):
|
809
809
|
r_to_sel, c_to_sel = self.MT.selected.row, self.MT.selected.column
|
810
|
-
self.
|
810
|
+
self.being_drawn_item = None
|
811
811
|
self.MT.set_currently_selected(
|
812
812
|
r_to_sel,
|
813
813
|
c_to_sel,
|
814
814
|
item=self.MT.create_selection_box(*to_sel, set_current=False),
|
815
|
+
run_binding=False,
|
815
816
|
)
|
816
|
-
|
817
|
-
try_binding(self.drag_selection_binding_func, sel_event)
|
818
|
-
self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
|
819
|
-
else:
|
820
|
-
self.being_drawn_item = None
|
817
|
+
self.MT.hide_selection_box(to_hide)
|
821
818
|
self.MT.bind("<MouseWheel>", self.MT.mousewheel)
|
822
819
|
if self.width_resizing_enabled and self.rsz_w is not None and self.currently_resizing_width:
|
823
820
|
self.drag_width_resize()
|
@@ -1190,45 +1187,44 @@ class ColumnHeaders(tk.Canvas):
|
|
1190
1187
|
fc: float,
|
1191
1188
|
sc: float,
|
1192
1189
|
c: int,
|
1193
|
-
|
1194
|
-
|
1190
|
+
sel_cells_bg: str,
|
1191
|
+
sel_cols_bg: str,
|
1195
1192
|
selections: dict,
|
1196
1193
|
datacn: int,
|
1197
1194
|
) -> tuple[str, bool]:
|
1198
1195
|
redrawn = False
|
1199
1196
|
kwargs = self.get_cell_kwargs(datacn, key="highlight")
|
1200
1197
|
if kwargs:
|
1201
|
-
|
1202
|
-
|
1198
|
+
fill = kwargs[0]
|
1199
|
+
if fill and not fill.startswith("#"):
|
1200
|
+
fill = color_map[fill]
|
1203
1201
|
if "columns" in selections and c in selections["columns"]:
|
1204
|
-
|
1202
|
+
txtfg = (
|
1205
1203
|
self.PAR.ops.header_selected_columns_fg
|
1206
1204
|
if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
|
1207
1205
|
else kwargs[1]
|
1208
1206
|
)
|
1209
|
-
if
|
1207
|
+
if fill:
|
1210
1208
|
fill = (
|
1211
|
-
f"#{int((int(
|
1212
|
-
+ f"{int((int(
|
1213
|
-
+ f"{int((int(
|
1209
|
+
f"#{int((int(fill[1:3], 16) + int(sel_cols_bg[1:3], 16)) / 2):02X}"
|
1210
|
+
+ f"{int((int(fill[3:5], 16) + int(sel_cols_bg[3:5], 16)) / 2):02X}"
|
1211
|
+
+ f"{int((int(fill[5:], 16) + int(sel_cols_bg[5:], 16)) / 2):02X}"
|
1214
1212
|
)
|
1215
1213
|
elif "cells" in selections and c in selections["cells"]:
|
1216
|
-
|
1214
|
+
txtfg = (
|
1217
1215
|
self.PAR.ops.header_selected_cells_fg
|
1218
1216
|
if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
|
1219
1217
|
else kwargs[1]
|
1220
1218
|
)
|
1221
|
-
if
|
1219
|
+
if fill:
|
1222
1220
|
fill = (
|
1223
|
-
f"#{int((int(
|
1224
|
-
+ f"{int((int(
|
1225
|
-
+ f"{int((int(
|
1221
|
+
f"#{int((int(fill[1:3], 16) + int(sel_cells_bg[1:3], 16)) / 2):02X}"
|
1222
|
+
+ f"{int((int(fill[3:5], 16) + int(sel_cells_bg[3:5], 16)) / 2):02X}"
|
1223
|
+
+ f"{int((int(fill[5:], 16) + int(sel_cells_bg[5:], 16)) / 2):02X}"
|
1226
1224
|
)
|
1227
1225
|
else:
|
1228
|
-
|
1229
|
-
|
1230
|
-
fill = kwargs[0]
|
1231
|
-
if kwargs[0] is not None:
|
1226
|
+
txtfg = self.PAR.ops.header_fg if kwargs[1] is None else kwargs[1]
|
1227
|
+
if fill:
|
1232
1228
|
redrawn = self.redraw_highlight(
|
1233
1229
|
fc + 1,
|
1234
1230
|
0,
|
@@ -1244,12 +1240,12 @@ class ColumnHeaders(tk.Canvas):
|
|
1244
1240
|
)
|
1245
1241
|
elif not kwargs:
|
1246
1242
|
if "columns" in selections and c in selections["columns"]:
|
1247
|
-
|
1243
|
+
txtfg = self.PAR.ops.header_selected_columns_fg
|
1248
1244
|
elif "cells" in selections and c in selections["cells"]:
|
1249
|
-
|
1245
|
+
txtfg = self.PAR.ops.header_selected_cells_fg
|
1250
1246
|
else:
|
1251
|
-
|
1252
|
-
return
|
1247
|
+
txtfg = self.PAR.ops.header_fg
|
1248
|
+
return txtfg, redrawn
|
1253
1249
|
|
1254
1250
|
def redraw_highlight(
|
1255
1251
|
self,
|
@@ -1463,12 +1459,12 @@ class ColumnHeaders(tk.Canvas):
|
|
1463
1459
|
)
|
1464
1460
|
self.redraw_gridline(points=points, fill=self.PAR.ops.header_grid_fg, width=1, tag="v")
|
1465
1461
|
top = self.canvasy(0)
|
1466
|
-
|
1462
|
+
sel_cols_bg = (
|
1467
1463
|
self.PAR.ops.header_selected_cells_bg
|
1468
1464
|
if self.PAR.ops.header_selected_cells_bg.startswith("#")
|
1469
1465
|
else color_map[self.PAR.ops.header_selected_cells_bg]
|
1470
1466
|
)
|
1471
|
-
|
1467
|
+
sel_cells_bg = (
|
1472
1468
|
self.PAR.ops.header_selected_columns_bg
|
1473
1469
|
if self.PAR.ops.header_selected_columns_bg.startswith("#")
|
1474
1470
|
else color_map[self.PAR.ops.header_selected_columns_bg]
|
@@ -1482,7 +1478,13 @@ class ColumnHeaders(tk.Canvas):
|
|
1482
1478
|
crightgridln = self.MT.col_positions[c + 1]
|
1483
1479
|
datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
|
1484
1480
|
fill, dd_drawn = self.redraw_highlight_get_text_fg(
|
1485
|
-
cleftgridln,
|
1481
|
+
fc=cleftgridln,
|
1482
|
+
sc=crightgridln,
|
1483
|
+
c=c,
|
1484
|
+
sel_cells_bg=sel_cells_bg,
|
1485
|
+
sel_cols_bg=sel_cols_bg,
|
1486
|
+
selections=selections,
|
1487
|
+
datacn=datacn,
|
1486
1488
|
)
|
1487
1489
|
|
1488
1490
|
if datacn in self.cell_options and "align" in self.cell_options[datacn]:
|
@@ -1500,7 +1502,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1500
1502
|
0,
|
1501
1503
|
crightgridln,
|
1502
1504
|
self.current_height - 1,
|
1503
|
-
fill=fill,
|
1505
|
+
fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.header_grid_fg,
|
1504
1506
|
outline=fill,
|
1505
1507
|
tag="dd",
|
1506
1508
|
draw_outline=not dd_drawn,
|
@@ -1519,7 +1521,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1519
1521
|
0,
|
1520
1522
|
crightgridln,
|
1521
1523
|
self.current_height - 1,
|
1522
|
-
fill=fill,
|
1524
|
+
fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.header_grid_fg,
|
1523
1525
|
outline=fill,
|
1524
1526
|
tag="dd",
|
1525
1527
|
draw_outline=not dd_drawn,
|
@@ -1539,7 +1541,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1539
1541
|
0,
|
1540
1542
|
crightgridln,
|
1541
1543
|
self.current_height - 1,
|
1542
|
-
fill=fill,
|
1544
|
+
fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.header_grid_fg,
|
1543
1545
|
outline=fill,
|
1544
1546
|
tag="dd",
|
1545
1547
|
draw_outline=not dd_drawn,
|
@@ -1768,7 +1770,6 @@ class ColumnHeaders(tk.Canvas):
|
|
1768
1770
|
h = self.current_height + 1
|
1769
1771
|
if text is None:
|
1770
1772
|
text = self.get_cell_data(self.MT.datacn(c), none_to_empty_str=True, redirect_int=True)
|
1771
|
-
bg, fg = self.PAR.ops.header_bg, self.PAR.ops.header_fg
|
1772
1773
|
kwargs = {
|
1773
1774
|
"menu_kwargs": DotDict(
|
1774
1775
|
{
|
@@ -1786,8 +1787,10 @@ class ColumnHeaders(tk.Canvas):
|
|
1786
1787
|
"width": w,
|
1787
1788
|
"height": h,
|
1788
1789
|
"show_border": True,
|
1789
|
-
"bg":
|
1790
|
-
"fg":
|
1790
|
+
"bg": self.PAR.ops.header_editor_bg,
|
1791
|
+
"fg": self.PAR.ops.header_editor_fg,
|
1792
|
+
"select_bg": self.PAR.ops.header_editor_select_bg,
|
1793
|
+
"select_fg": self.PAR.ops.header_editor_select_fg,
|
1791
1794
|
"align": self.get_cell_align(c),
|
1792
1795
|
"c": c,
|
1793
1796
|
}
|
@@ -1999,26 +2002,46 @@ class ColumnHeaders(tk.Canvas):
|
|
1999
2002
|
|
2000
2003
|
def dropdown_text_editor_modified(
|
2001
2004
|
self,
|
2002
|
-
|
2003
|
-
event: dict,
|
2004
|
-
modified_func: Callable | None,
|
2005
|
+
event: tk.Misc,
|
2005
2006
|
) -> None:
|
2006
|
-
|
2007
|
-
|
2008
|
-
|
2007
|
+
c = self.dropdown.get_coords()
|
2008
|
+
event_data = event_dict(
|
2009
|
+
name="table_dropdown_modified",
|
2010
|
+
sheet=self.PAR.name,
|
2011
|
+
value=self.text_editor.get(),
|
2012
|
+
loc=c,
|
2013
|
+
row=0,
|
2014
|
+
column=c,
|
2015
|
+
boxes=self.MT.get_boxes(),
|
2016
|
+
selected=self.MT.selected,
|
2017
|
+
)
|
2018
|
+
try_binding(self.dropdown.window.modified_function, event_data)
|
2019
|
+
# return to tk.Text action if control/command is held down
|
2020
|
+
# or keysym was not a character
|
2021
|
+
if (hasattr(event, "state") and event.state & (0x0004 | 0x00000010)) or (
|
2022
|
+
hasattr(event, "keysym") and len(event.keysym) > 2 and event.keysym != "space"
|
2023
|
+
):
|
2024
|
+
return
|
2025
|
+
self.text_editor.autocomplete(self.dropdown.window.search_and_see(event_data))
|
2026
|
+
return "break"
|
2009
2027
|
|
2010
2028
|
def open_dropdown_window(self, c: int, event: object = None) -> None:
|
2011
2029
|
self.hide_text_editor()
|
2012
2030
|
kwargs = self.get_cell_kwargs(self.MT.datacn(c), key="dropdown")
|
2013
|
-
if kwargs["state"] == "
|
2014
|
-
|
2015
|
-
|
2031
|
+
if kwargs["state"] == "disabled":
|
2032
|
+
return
|
2033
|
+
if kwargs["state"] == "normal" and not self.open_text_editor(event=event, c=c, dropdown=True):
|
2034
|
+
return
|
2016
2035
|
win_h, anchor = self.get_dropdown_height_anchor(c)
|
2017
2036
|
win_w = self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1
|
2018
2037
|
ypos = self.current_height - 1
|
2019
2038
|
reset_kwargs = {
|
2020
2039
|
"r": 0,
|
2021
2040
|
"c": c,
|
2041
|
+
"bg": self.PAR.ops.header_editor_bg,
|
2042
|
+
"fg": self.PAR.ops.header_editor_fg,
|
2043
|
+
"select_bg": self.PAR.ops.header_editor_select_bg,
|
2044
|
+
"select_fg": self.PAR.ops.header_editor_select_fg,
|
2022
2045
|
"width": win_w,
|
2023
2046
|
"height": win_h,
|
2024
2047
|
"font": self.PAR.ops.header_font,
|
@@ -2026,6 +2049,8 @@ class ColumnHeaders(tk.Canvas):
|
|
2026
2049
|
"outline_color": self.PAR.ops.header_selected_columns_bg,
|
2027
2050
|
"align": self.get_cell_align(c),
|
2028
2051
|
"values": kwargs["values"],
|
2052
|
+
"search_function": kwargs["search_function"],
|
2053
|
+
"modified_function": kwargs["modified_function"],
|
2029
2054
|
}
|
2030
2055
|
if self.dropdown.window:
|
2031
2056
|
self.dropdown.window.reset(**reset_kwargs)
|
@@ -2038,7 +2063,6 @@ class ColumnHeaders(tk.Canvas):
|
|
2038
2063
|
**reset_kwargs,
|
2039
2064
|
single_index="c",
|
2040
2065
|
close_dropdown_window=self.close_dropdown_window,
|
2041
|
-
search_function=kwargs["search_function"],
|
2042
2066
|
arrowkey_RIGHT=self.MT.arrowkey_RIGHT,
|
2043
2067
|
arrowkey_LEFT=self.MT.arrowkey_LEFT,
|
2044
2068
|
)
|
@@ -2047,24 +2071,12 @@ class ColumnHeaders(tk.Canvas):
|
|
2047
2071
|
window=self.dropdown.window,
|
2048
2072
|
anchor=anchor,
|
2049
2073
|
)
|
2074
|
+
self.update_idletasks()
|
2050
2075
|
if kwargs["state"] == "normal":
|
2051
2076
|
self.text_editor.tktext.bind(
|
2052
|
-
"
|
2053
|
-
|
2054
|
-
self.dropdown.window,
|
2055
|
-
event_dict(
|
2056
|
-
name="header_dropdown_modified",
|
2057
|
-
sheet=self.PAR.name,
|
2058
|
-
value=self.text_editor.get(),
|
2059
|
-
loc=c,
|
2060
|
-
column=c,
|
2061
|
-
boxes=self.MT.get_boxes(),
|
2062
|
-
selected=self.MT.selected,
|
2063
|
-
),
|
2064
|
-
kwargs["modified_function"],
|
2065
|
-
),
|
2077
|
+
"<KeyRelease>",
|
2078
|
+
self.dropdown_text_editor_modified,
|
2066
2079
|
)
|
2067
|
-
self.update_idletasks()
|
2068
2080
|
try:
|
2069
2081
|
self.after(1, lambda: self.text_editor.tktext.focus())
|
2070
2082
|
self.after(2, self.text_editor.window.scroll_to_bottom())
|
@@ -2072,7 +2084,6 @@ class ColumnHeaders(tk.Canvas):
|
|
2072
2084
|
return
|
2073
2085
|
redraw = False
|
2074
2086
|
else:
|
2075
|
-
self.update_idletasks()
|
2076
2087
|
self.dropdown.window.bind("<FocusOut>", lambda _x: self.close_dropdown_window(c))
|
2077
2088
|
self.dropdown.window.bind("<Escape>", self.close_dropdown_window)
|
2078
2089
|
self.dropdown.window.focus_set()
|
@@ -18,6 +18,7 @@ from collections.abc import (
|
|
18
18
|
from itertools import islice, repeat
|
19
19
|
from typing import Literal
|
20
20
|
|
21
|
+
from .colors import color_map
|
21
22
|
from .formatters import (
|
22
23
|
to_bool,
|
23
24
|
)
|
@@ -426,6 +427,20 @@ def is_contiguous(iterable: Iterator[int]) -> bool:
|
|
426
427
|
return all(i == (prev := prev + 1) for i in itr)
|
427
428
|
|
428
429
|
|
430
|
+
def box_is_single_cell(
|
431
|
+
r1: int,
|
432
|
+
c1: int,
|
433
|
+
r2: int,
|
434
|
+
c2: int,
|
435
|
+
) -> bool:
|
436
|
+
return r2 - r1 == 1 and c2 - c1 == 1
|
437
|
+
|
438
|
+
|
439
|
+
def color_tup(color: str) -> tuple[int, int, int]:
|
440
|
+
res = color if color.startswith("#") else color_map[color]
|
441
|
+
return int(res[1:3], 16), int(res[3:5], 16), int(res[5:], 16)
|
442
|
+
|
443
|
+
|
429
444
|
def down_cell_within_box(
|
430
445
|
r: int,
|
431
446
|
c: int,
|
@@ -1400,12 +1415,24 @@ def mod_span_widget(span: Span, widget: object) -> Span:
|
|
1400
1415
|
def mod_event_val(
|
1401
1416
|
event_data: EventDataDict,
|
1402
1417
|
val: object,
|
1403
|
-
loc: Loc |
|
1418
|
+
loc: Loc | None = None,
|
1419
|
+
row: int | None = None,
|
1420
|
+
column: int | None = None,
|
1404
1421
|
) -> EventDataDict:
|
1405
1422
|
event_data.value = val
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1423
|
+
if isinstance(loc, tuple):
|
1424
|
+
event_data.loc = Loc(*loc)
|
1425
|
+
event_data.row = loc[0]
|
1426
|
+
event_data.column = loc[1]
|
1427
|
+
|
1428
|
+
elif isinstance(row, int):
|
1429
|
+
event_data.loc = Loc(row=row)
|
1430
|
+
event_data.row = row
|
1431
|
+
|
1432
|
+
elif isinstance(column, int):
|
1433
|
+
event_data.loc = Loc(column=column)
|
1434
|
+
event_data.column = column
|
1435
|
+
|
1409
1436
|
return event_data
|
1410
1437
|
|
1411
1438
|
|