tksheet 7.1.21__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 +35 -22
- tksheet/functions.py +27 -5
- tksheet/main_table.py +114 -53
- tksheet/row_index.py +42 -29
- tksheet/sheet.py +317 -261
- tksheet/sheet_options.py +1 -1
- tksheet/text_editor.py +1 -5
- tksheet/themes.py +41 -32
- tksheet/vars.py +22 -9
- {tksheet-7.1.21.dist-info → tksheet-7.1.22.dist-info}/METADATA +5 -5
- tksheet-7.1.22.dist-info/RECORD +20 -0
- tksheet-7.1.21.dist-info/RECORD +0 -20
- {tksheet-7.1.21.dist-info → tksheet-7.1.22.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.1.21.dist-info → tksheet-7.1.22.dist-info}/WHEEL +0 -0
- {tksheet-7.1.21.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"] = {
|
@@ -1730,21 +1742,16 @@ class ColumnHeaders(tk.Canvas):
|
|
1730
1742
|
self.itemconfig(self.text_editor.canvas_id, state="normal")
|
1731
1743
|
self.text_editor.open = True
|
1732
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)
|
1733
1749
|
if not dropdown:
|
1734
1750
|
self.text_editor.tktext.focus_set()
|
1735
1751
|
self.text_editor.window.scroll_to_bottom()
|
1736
|
-
|
1737
|
-
self.text_editor.tktext.bind("<Alt-KP_Enter>", lambda _x: self.text_editor_newline_binding(c=c))
|
1738
|
-
if USER_OS == "darwin":
|
1739
|
-
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)
|
1740
1753
|
for key, func in self.MT.text_editor_user_bound_keys.items():
|
1741
1754
|
self.text_editor.tktext.bind(key, func)
|
1742
|
-
self.text_editor.tktext.bind("<Tab>", lambda _x: self.close_text_editor((c, "Tab")))
|
1743
|
-
self.text_editor.tktext.bind("<Return>", lambda _x: self.close_text_editor((c, "Return")))
|
1744
|
-
self.text_editor.tktext.bind("<KP_Enter>", lambda _x: self.close_text_editor((c, "Return")))
|
1745
|
-
if not dropdown:
|
1746
|
-
self.text_editor.tktext.bind("<FocusOut>", lambda _x: self.close_text_editor((c, "FocusOut")))
|
1747
|
-
self.text_editor.tktext.bind("<Escape>", lambda _x: self.close_text_editor((c, "Escape")))
|
1748
1755
|
return True
|
1749
1756
|
|
1750
1757
|
# displayed indexes #just here to receive text editor arg
|
@@ -1763,7 +1770,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1763
1770
|
self.coords(self.text_editor.canvas_id, self.MT.col_positions[c] + 1, 0)
|
1764
1771
|
|
1765
1772
|
# displayed indexes
|
1766
|
-
def text_editor_newline_binding(self,
|
1773
|
+
def text_editor_newline_binding(self, event: object = None, check_lines=True):
|
1767
1774
|
if not self.height_resizing_enabled:
|
1768
1775
|
return
|
1769
1776
|
curr_height = self.text_editor.window.winfo_height()
|
@@ -1777,6 +1784,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1777
1784
|
)
|
1778
1785
|
> curr_height
|
1779
1786
|
):
|
1787
|
+
c = self.text_editor.column
|
1780
1788
|
new_height = curr_height + self.MT.header_xtra_lines_increment
|
1781
1789
|
space_bot = self.MT.get_space_bot(0)
|
1782
1790
|
if new_height > space_bot:
|
@@ -1845,31 +1853,33 @@ class ColumnHeaders(tk.Canvas):
|
|
1845
1853
|
self.focus_set()
|
1846
1854
|
|
1847
1855
|
# c is displayed col
|
1848
|
-
def close_text_editor(
|
1849
|
-
self,
|
1850
|
-
editor_info: tuple,
|
1851
|
-
):
|
1856
|
+
def close_text_editor(self, event: tk.Event) -> Literal["break"] | None:
|
1852
1857
|
# checking if text editor should be closed or not
|
1853
|
-
|
1858
|
+
# errors if __tk_filedialog is open
|
1859
|
+
try:
|
1860
|
+
focused = self.focus_get()
|
1861
|
+
except Exception:
|
1862
|
+
focused = None
|
1854
1863
|
try:
|
1855
1864
|
if focused == self.text_editor.tktext.rc_popup_menu:
|
1856
1865
|
return "break"
|
1857
1866
|
except Exception:
|
1858
1867
|
pass
|
1859
|
-
if focused is None
|
1868
|
+
if focused is None:
|
1860
1869
|
return "break"
|
1861
|
-
if
|
1870
|
+
if event.keysym == "Escape":
|
1862
1871
|
self.hide_text_editor_and_dropdown()
|
1863
1872
|
return
|
1864
1873
|
# setting cell data with text editor value
|
1865
1874
|
text_editor_value = self.text_editor.get()
|
1866
|
-
c =
|
1875
|
+
c = self.text_editor.column
|
1867
1876
|
datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
|
1868
1877
|
event_data = event_dict(
|
1869
1878
|
name="end_edit_header",
|
1870
1879
|
sheet=self.PAR.name,
|
1880
|
+
widget=self,
|
1871
1881
|
cells_header={datacn: self.get_cell_data(datacn)},
|
1872
|
-
key=
|
1882
|
+
key=event.keysym,
|
1873
1883
|
value=text_editor_value,
|
1874
1884
|
loc=c,
|
1875
1885
|
column=c,
|
@@ -1893,7 +1903,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1893
1903
|
try_binding(self.extra_end_edit_cell_func, event_data)
|
1894
1904
|
self.MT.recreate_all_selection_boxes()
|
1895
1905
|
self.hide_text_editor_and_dropdown()
|
1896
|
-
if
|
1906
|
+
if event.keysym != "FocusOut":
|
1897
1907
|
self.focus_set()
|
1898
1908
|
return "break"
|
1899
1909
|
|
@@ -2014,6 +2024,7 @@ class ColumnHeaders(tk.Canvas):
|
|
2014
2024
|
event_data = event_dict(
|
2015
2025
|
name="end_edit_header",
|
2016
2026
|
sheet=self.PAR.name,
|
2027
|
+
widget=self,
|
2017
2028
|
cells_header={datacn: pre_edit_value},
|
2018
2029
|
key="??",
|
2019
2030
|
value=selection,
|
@@ -2045,7 +2056,7 @@ class ColumnHeaders(tk.Canvas):
|
|
2045
2056
|
def mouseclick_outside_editor_or_dropdown(self, inside: bool = False):
|
2046
2057
|
closed_dd_coords = self.dropdown.get_coords()
|
2047
2058
|
if self.text_editor.open:
|
2048
|
-
self.close_text_editor((
|
2059
|
+
self.close_text_editor(new_tk_event("ButtonPress-1"))
|
2049
2060
|
if closed_dd_coords is not None:
|
2050
2061
|
self.hide_dropdown_window()
|
2051
2062
|
if inside:
|
@@ -2083,6 +2094,7 @@ class ColumnHeaders(tk.Canvas):
|
|
2083
2094
|
event_data = event_dict(
|
2084
2095
|
name="edit_header",
|
2085
2096
|
sheet=self.PAR.name,
|
2097
|
+
widget=self,
|
2086
2098
|
cells_header={datacn: self.get_cell_data(datacn)},
|
2087
2099
|
boxes=self.MT.get_boxes(),
|
2088
2100
|
selected=self.MT.selected,
|
@@ -2240,6 +2252,7 @@ class ColumnHeaders(tk.Canvas):
|
|
2240
2252
|
event_data = event_dict(
|
2241
2253
|
name="end_edit_header",
|
2242
2254
|
sheet=self.PAR.name,
|
2255
|
+
widget=self,
|
2243
2256
|
cells_header={datacn: pre_edit_value},
|
2244
2257
|
key="??",
|
2245
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
|
|