tksheet 7.1.20__py3-none-any.whl → 7.1.22__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 +5 -1
- tksheet/column_headers.py +36 -26
- tksheet/functions.py +27 -5
- tksheet/main_table.py +116 -58
- tksheet/row_index.py +149 -94
- tksheet/sheet.py +317 -261
- tksheet/sheet_options.py +4 -1
- tksheet/text_editor.py +1 -5
- tksheet/themes.py +51 -30
- tksheet/vars.py +22 -9
- {tksheet-7.1.20.dist-info → tksheet-7.1.22.dist-info}/METADATA +5 -5
- tksheet-7.1.22.dist-info/RECORD +20 -0
- tksheet-7.1.20.dist-info/RECORD +0 -20
- {tksheet-7.1.20.dist-info → tksheet-7.1.22.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.1.20.dist-info → tksheet-7.1.22.dist-info}/WHEEL +0 -0
- {tksheet-7.1.20.dist-info → tksheet-7.1.22.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.1.
|
7
|
+
__version__ = "7.1.22"
|
8
8
|
|
9
9
|
from .colors import (
|
10
10
|
color_map,
|
@@ -32,6 +32,7 @@ from .formatters import (
|
|
32
32
|
try_to_bool,
|
33
33
|
)
|
34
34
|
from .functions import (
|
35
|
+
add_highlight,
|
35
36
|
alpha2idx,
|
36
37
|
alpha2num,
|
37
38
|
consecutive_chunks,
|
@@ -42,6 +43,7 @@ from .functions import (
|
|
42
43
|
event_dict,
|
43
44
|
get_checkbox_dict,
|
44
45
|
get_checkbox_kwargs,
|
46
|
+
get_csv_str_dialect,
|
45
47
|
get_data_from_clipboard,
|
46
48
|
get_dropdown_dict,
|
47
49
|
get_dropdown_kwargs,
|
@@ -54,6 +56,7 @@ from .functions import (
|
|
54
56
|
is_iterable,
|
55
57
|
move_elements_by_mapping,
|
56
58
|
move_elements_to,
|
59
|
+
new_tk_event,
|
57
60
|
num2alpha,
|
58
61
|
rounded_box_coords,
|
59
62
|
span_dict,
|
@@ -66,6 +69,7 @@ from .other_classes import (
|
|
66
69
|
DrawnItem,
|
67
70
|
EventDataDict,
|
68
71
|
GeneratedMouseEvent,
|
72
|
+
Highlight,
|
69
73
|
Selected,
|
70
74
|
Span,
|
71
75
|
SpanRange,
|
tksheet/column_headers.py
CHANGED
@@ -25,6 +25,7 @@ from .functions import (
|
|
25
25
|
event_dict,
|
26
26
|
get_n2a,
|
27
27
|
is_contiguous,
|
28
|
+
new_tk_event,
|
28
29
|
pickled_event_dict,
|
29
30
|
rounded_box_coords,
|
30
31
|
try_binding,
|
@@ -42,6 +43,8 @@ from .vars import (
|
|
42
43
|
USER_OS,
|
43
44
|
rc_binding,
|
44
45
|
symbols_set,
|
46
|
+
text_editor_close_bindings,
|
47
|
+
text_editor_newline_bindings,
|
45
48
|
text_editor_to_unbind,
|
46
49
|
)
|
47
50
|
|
@@ -124,6 +127,13 @@ class ColumnHeaders(tk.Canvas):
|
|
124
127
|
self.align = kwargs["header_align"]
|
125
128
|
self.basic_bindings()
|
126
129
|
|
130
|
+
def event_generate(self, *args, **kwargs) -> None:
|
131
|
+
for arg in args:
|
132
|
+
if self.MT and arg in self.MT.event_linker:
|
133
|
+
self.MT.event_linker[arg]()
|
134
|
+
else:
|
135
|
+
super().event_generate(*args, **kwargs)
|
136
|
+
|
127
137
|
def basic_bindings(self, enable: bool = True):
|
128
138
|
if enable:
|
129
139
|
self.bind("<Motion>", self.mouse_motion)
|
@@ -833,6 +843,7 @@ class ColumnHeaders(tk.Canvas):
|
|
833
843
|
event_data = event_dict(
|
834
844
|
name="move_columns",
|
835
845
|
sheet=self.PAR.name,
|
846
|
+
widget=self,
|
836
847
|
boxes=self.MT.get_boxes(),
|
837
848
|
selected=self.MT.selected,
|
838
849
|
value=c,
|
@@ -844,6 +855,7 @@ class ColumnHeaders(tk.Canvas):
|
|
844
855
|
to_move=self.dragged_col.to_move,
|
845
856
|
),
|
846
857
|
move_data=self.PAR.ops.column_drag_and_drop_perform,
|
858
|
+
move_widths=self.PAR.ops.column_drag_and_drop_perform,
|
847
859
|
event_data=event_data,
|
848
860
|
)
|
849
861
|
event_data["moved"]["columns"] = {
|
@@ -1284,12 +1296,9 @@ class ColumnHeaders(tk.Canvas):
|
|
1284
1296
|
self.itemconfig(t, fill=fill, tag=tag, state="normal")
|
1285
1297
|
self.lift(t)
|
1286
1298
|
else:
|
1287
|
-
t = self.
|
1299
|
+
t = self.create_polygon(
|
1288
1300
|
points,
|
1289
1301
|
fill=fill,
|
1290
|
-
width=2,
|
1291
|
-
capstyle=tk.ROUND,
|
1292
|
-
joinstyle=tk.ROUND,
|
1293
1302
|
tag=tag,
|
1294
1303
|
)
|
1295
1304
|
self.disp_dropdown[t] = True
|
@@ -1733,21 +1742,16 @@ class ColumnHeaders(tk.Canvas):
|
|
1733
1742
|
self.itemconfig(self.text_editor.canvas_id, state="normal")
|
1734
1743
|
self.text_editor.open = True
|
1735
1744
|
self.coords(self.text_editor.canvas_id, x, y)
|
1745
|
+
for b in text_editor_newline_bindings:
|
1746
|
+
self.text_editor.tktext.bind(b, self.text_editor_newline_binding)
|
1747
|
+
for b in text_editor_close_bindings:
|
1748
|
+
self.text_editor.tktext.bind(b, self.close_text_editor)
|
1736
1749
|
if not dropdown:
|
1737
1750
|
self.text_editor.tktext.focus_set()
|
1738
1751
|
self.text_editor.window.scroll_to_bottom()
|
1739
|
-
|
1740
|
-
self.text_editor.tktext.bind("<Alt-KP_Enter>", lambda _x: self.text_editor_newline_binding(c=c))
|
1741
|
-
if USER_OS == "darwin":
|
1742
|
-
self.text_editor.tktext.bind("<Option-Return>", lambda _x: self.text_editor_newline_binding(c=c))
|
1752
|
+
self.text_editor.tktext.bind("<FocusOut>", self.close_text_editor)
|
1743
1753
|
for key, func in self.MT.text_editor_user_bound_keys.items():
|
1744
1754
|
self.text_editor.tktext.bind(key, func)
|
1745
|
-
self.text_editor.tktext.bind("<Tab>", lambda _x: self.close_text_editor((c, "Tab")))
|
1746
|
-
self.text_editor.tktext.bind("<Return>", lambda _x: self.close_text_editor((c, "Return")))
|
1747
|
-
self.text_editor.tktext.bind("<KP_Enter>", lambda _x: self.close_text_editor((c, "Return")))
|
1748
|
-
if not dropdown:
|
1749
|
-
self.text_editor.tktext.bind("<FocusOut>", lambda _x: self.close_text_editor((c, "FocusOut")))
|
1750
|
-
self.text_editor.tktext.bind("<Escape>", lambda _x: self.close_text_editor((c, "Escape")))
|
1751
1755
|
return True
|
1752
1756
|
|
1753
1757
|
# displayed indexes #just here to receive text editor arg
|
@@ -1766,7 +1770,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1766
1770
|
self.coords(self.text_editor.canvas_id, self.MT.col_positions[c] + 1, 0)
|
1767
1771
|
|
1768
1772
|
# displayed indexes
|
1769
|
-
def text_editor_newline_binding(self,
|
1773
|
+
def text_editor_newline_binding(self, event: object = None, check_lines=True):
|
1770
1774
|
if not self.height_resizing_enabled:
|
1771
1775
|
return
|
1772
1776
|
curr_height = self.text_editor.window.winfo_height()
|
@@ -1780,6 +1784,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1780
1784
|
)
|
1781
1785
|
> curr_height
|
1782
1786
|
):
|
1787
|
+
c = self.text_editor.column
|
1783
1788
|
new_height = curr_height + self.MT.header_xtra_lines_increment
|
1784
1789
|
space_bot = self.MT.get_space_bot(0)
|
1785
1790
|
if new_height > space_bot:
|
@@ -1848,31 +1853,33 @@ class ColumnHeaders(tk.Canvas):
|
|
1848
1853
|
self.focus_set()
|
1849
1854
|
|
1850
1855
|
# c is displayed col
|
1851
|
-
def close_text_editor(
|
1852
|
-
self,
|
1853
|
-
editor_info: tuple,
|
1854
|
-
):
|
1856
|
+
def close_text_editor(self, event: tk.Event) -> Literal["break"] | None:
|
1855
1857
|
# checking if text editor should be closed or not
|
1856
|
-
|
1858
|
+
# errors if __tk_filedialog is open
|
1859
|
+
try:
|
1860
|
+
focused = self.focus_get()
|
1861
|
+
except Exception:
|
1862
|
+
focused = None
|
1857
1863
|
try:
|
1858
1864
|
if focused == self.text_editor.tktext.rc_popup_menu:
|
1859
1865
|
return "break"
|
1860
1866
|
except Exception:
|
1861
1867
|
pass
|
1862
|
-
if focused is None
|
1868
|
+
if focused is None:
|
1863
1869
|
return "break"
|
1864
|
-
if
|
1870
|
+
if event.keysym == "Escape":
|
1865
1871
|
self.hide_text_editor_and_dropdown()
|
1866
1872
|
return
|
1867
1873
|
# setting cell data with text editor value
|
1868
1874
|
text_editor_value = self.text_editor.get()
|
1869
|
-
c =
|
1875
|
+
c = self.text_editor.column
|
1870
1876
|
datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
|
1871
1877
|
event_data = event_dict(
|
1872
1878
|
name="end_edit_header",
|
1873
1879
|
sheet=self.PAR.name,
|
1880
|
+
widget=self,
|
1874
1881
|
cells_header={datacn: self.get_cell_data(datacn)},
|
1875
|
-
key=
|
1882
|
+
key=event.keysym,
|
1876
1883
|
value=text_editor_value,
|
1877
1884
|
loc=c,
|
1878
1885
|
column=c,
|
@@ -1896,7 +1903,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1896
1903
|
try_binding(self.extra_end_edit_cell_func, event_data)
|
1897
1904
|
self.MT.recreate_all_selection_boxes()
|
1898
1905
|
self.hide_text_editor_and_dropdown()
|
1899
|
-
if
|
1906
|
+
if event.keysym != "FocusOut":
|
1900
1907
|
self.focus_set()
|
1901
1908
|
return "break"
|
1902
1909
|
|
@@ -2017,6 +2024,7 @@ class ColumnHeaders(tk.Canvas):
|
|
2017
2024
|
event_data = event_dict(
|
2018
2025
|
name="end_edit_header",
|
2019
2026
|
sheet=self.PAR.name,
|
2027
|
+
widget=self,
|
2020
2028
|
cells_header={datacn: pre_edit_value},
|
2021
2029
|
key="??",
|
2022
2030
|
value=selection,
|
@@ -2048,7 +2056,7 @@ class ColumnHeaders(tk.Canvas):
|
|
2048
2056
|
def mouseclick_outside_editor_or_dropdown(self, inside: bool = False):
|
2049
2057
|
closed_dd_coords = self.dropdown.get_coords()
|
2050
2058
|
if self.text_editor.open:
|
2051
|
-
self.close_text_editor((
|
2059
|
+
self.close_text_editor(new_tk_event("ButtonPress-1"))
|
2052
2060
|
if closed_dd_coords is not None:
|
2053
2061
|
self.hide_dropdown_window()
|
2054
2062
|
if inside:
|
@@ -2086,6 +2094,7 @@ class ColumnHeaders(tk.Canvas):
|
|
2086
2094
|
event_data = event_dict(
|
2087
2095
|
name="edit_header",
|
2088
2096
|
sheet=self.PAR.name,
|
2097
|
+
widget=self,
|
2089
2098
|
cells_header={datacn: self.get_cell_data(datacn)},
|
2090
2099
|
boxes=self.MT.get_boxes(),
|
2091
2100
|
selected=self.MT.selected,
|
@@ -2243,6 +2252,7 @@ class ColumnHeaders(tk.Canvas):
|
|
2243
2252
|
event_data = event_dict(
|
2244
2253
|
name="end_edit_header",
|
2245
2254
|
sheet=self.PAR.name,
|
2255
|
+
widget=self,
|
2246
2256
|
cells_header={datacn: pre_edit_value},
|
2247
2257
|
key="??",
|
2248
2258
|
value=value,
|
tksheet/functions.py
CHANGED
@@ -17,6 +17,9 @@ from collections.abc import (
|
|
17
17
|
from functools import partial
|
18
18
|
from itertools import islice, repeat
|
19
19
|
|
20
|
+
from .formatters import (
|
21
|
+
to_bool,
|
22
|
+
)
|
20
23
|
from .other_classes import (
|
21
24
|
Box_nt,
|
22
25
|
DotDict,
|
@@ -31,16 +34,20 @@ pickle_obj = partial(pickle.dumps, protocol=pickle.HIGHEST_PROTOCOL)
|
|
31
34
|
unpickle_obj = pickle.loads
|
32
35
|
|
33
36
|
|
37
|
+
def get_csv_str_dialect(s: str, delimiters: str) -> csv.Dialect:
|
38
|
+
try:
|
39
|
+
return csv.Sniffer().sniff(s[:5000] if len(s) > 5000 else s, delimiters=delimiters)
|
40
|
+
except Exception:
|
41
|
+
return csv.excel_tab
|
42
|
+
|
43
|
+
|
34
44
|
def get_data_from_clipboard(
|
35
45
|
widget: tk.Misc,
|
36
46
|
delimiters: str,
|
37
47
|
lineterminator: str = "\n",
|
38
48
|
) -> list[list[str]]:
|
39
49
|
data = widget.clipboard_get()
|
40
|
-
|
41
|
-
dialect = csv.Sniffer().sniff(data, delimiters=delimiters)
|
42
|
-
except Exception:
|
43
|
-
dialect = csv.excel_tab
|
50
|
+
dialect = get_csv_str_dialect(data, delimiters=delimiters)
|
44
51
|
if dialect.delimiter in data or lineterminator in data:
|
45
52
|
return list(csv.reader(io.StringIO(data), dialect=dialect, skipinitialspace=True))
|
46
53
|
return [[data]]
|
@@ -59,6 +66,12 @@ def tksheet_type_error(kwarg: str, valid_types: list[str], not_type: object) ->
|
|
59
66
|
return f"Argument '{kwarg}' must be one of the following types: {valid_types}, " f"not {type(not_type)}."
|
60
67
|
|
61
68
|
|
69
|
+
def new_tk_event(keysym: str) -> tk.Event:
|
70
|
+
event = tk.Event()
|
71
|
+
event.keysym = keysym
|
72
|
+
return event
|
73
|
+
|
74
|
+
|
62
75
|
def dropdown_search_function(
|
63
76
|
search_for: object,
|
64
77
|
data: Sequence[object],
|
@@ -112,6 +125,7 @@ def selection_box_tup_to_dict(box: tuple) -> dict:
|
|
112
125
|
def event_dict(
|
113
126
|
name: str = None,
|
114
127
|
sheet: object = None,
|
128
|
+
widget: tk.Canvas | None = None,
|
115
129
|
boxes: None | dict | tuple = None,
|
116
130
|
cells_table: None | dict = None,
|
117
131
|
cells_header: None | dict = None,
|
@@ -176,6 +190,7 @@ def event_dict(
|
|
176
190
|
# "header": DotDict() if resized_header is None else resized_header,
|
177
191
|
# "index": DotDict() if resized_index is None else resized_index,
|
178
192
|
),
|
193
|
+
widget=widget,
|
179
194
|
)
|
180
195
|
|
181
196
|
|
@@ -184,7 +199,7 @@ def change_eventname(event_dict: EventDataDict, newname: str) -> EventDataDict:
|
|
184
199
|
|
185
200
|
|
186
201
|
def pickled_event_dict(d: DotDict) -> DotDict:
|
187
|
-
return DotDict(name=d["eventname"], data=pickle_compress(d))
|
202
|
+
return DotDict(name=d["eventname"], data=pickle_compress(DotDict({k: v for k, v in d.items() if k != "widget"})))
|
188
203
|
|
189
204
|
|
190
205
|
def len_to_idx(n: int) -> int:
|
@@ -281,6 +296,13 @@ def is_type_int(o: object) -> bool:
|
|
281
296
|
return isinstance(o, int) and not isinstance(o, bool)
|
282
297
|
|
283
298
|
|
299
|
+
def force_bool(o: object) -> bool:
|
300
|
+
try:
|
301
|
+
return to_bool(o)
|
302
|
+
except Exception:
|
303
|
+
return False
|
304
|
+
|
305
|
+
|
284
306
|
def str_to_coords(s: str) -> None | tuple[int]:
|
285
307
|
s = s.split(":")
|
286
308
|
|