tksheet 7.1.4__tar.gz → 7.1.6__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.1.4/tksheet.egg-info → tksheet-7.1.6}/PKG-INFO +1 -1
- {tksheet-7.1.4 → tksheet-7.1.6}/pyproject.toml +1 -1
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/__init__.py +1 -1
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/column_headers.py +91 -73
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/functions.py +39 -11
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/main_table.py +240 -163
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/row_index.py +100 -79
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/sheet.py +101 -73
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/text_editor.py +8 -6
- {tksheet-7.1.4 → tksheet-7.1.6/tksheet.egg-info}/PKG-INFO +1 -1
- {tksheet-7.1.4 → tksheet-7.1.6}/LICENSE.txt +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/README.md +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/setup.cfg +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/colors.py +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/formatters.py +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/other_classes.py +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/sheet_options.py +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/themes.py +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/top_left_rectangle.py +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/types.py +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet/vars.py +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet.egg-info/SOURCES.txt +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet.egg-info/dependency_links.txt +0 -0
- {tksheet-7.1.4 → tksheet-7.1.6}/tksheet.egg-info/top_level.txt +0 -0
@@ -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.1.
|
9
|
+
version = "7.1.6"
|
10
10
|
authors = [{ name = "ragardner", email = "github@ragardner.simplelogin.com" }]
|
11
11
|
requires-python = ">=3.8"
|
12
12
|
license = {file = "LICENSE.txt"}
|
@@ -13,13 +13,14 @@ from itertools import (
|
|
13
13
|
islice,
|
14
14
|
)
|
15
15
|
from math import ceil, floor
|
16
|
+
from typing import Literal
|
16
17
|
|
17
18
|
from .colors import (
|
18
19
|
color_map,
|
19
20
|
)
|
20
21
|
from .formatters import is_bool_like, try_to_bool
|
21
22
|
from .functions import (
|
22
|
-
|
23
|
+
consecutive_ranges,
|
23
24
|
ev_stack_dict,
|
24
25
|
event_dict,
|
25
26
|
get_checkbox_points,
|
@@ -272,7 +273,9 @@ class ColumnHeaders(tk.Canvas):
|
|
272
273
|
if self.MT.selected and self.MT.selected.type_ == "columns":
|
273
274
|
r_to_sel, c_to_sel = self.MT.selected.row, self.MT.selected.column
|
274
275
|
self.MT.deselect("all", redraw=False)
|
275
|
-
self.being_drawn_item = self.MT.create_selection_box(
|
276
|
+
self.being_drawn_item = self.MT.create_selection_box(
|
277
|
+
*self.get_shift_select_box(c, c_to_sel), "columns"
|
278
|
+
)
|
276
279
|
self.MT.set_currently_selected(r_to_sel, c_to_sel, self.being_drawn_item)
|
277
280
|
else:
|
278
281
|
self.being_drawn_item = self.select_col(c, run_binding_func=False)
|
@@ -685,10 +688,10 @@ class ColumnHeaders(tk.Canvas):
|
|
685
688
|
tag="move_columns",
|
686
689
|
)
|
687
690
|
self.MT.create_resize_line(xpos, y1, xpos, y2, width=3, fill=self.PAR.ops.drag_and_drop_bg, tag="move_columns")
|
688
|
-
for
|
691
|
+
for boxst, boxend in consecutive_ranges(cols):
|
689
692
|
self.MT.show_ctrl_outline(
|
690
|
-
start_cell=(
|
691
|
-
end_cell=(
|
693
|
+
start_cell=(boxst, 0),
|
694
|
+
end_cell=(boxend, len(self.MT.row_positions) - 1),
|
692
695
|
dash=(),
|
693
696
|
outline=self.PAR.ops.drag_and_drop_bg,
|
694
697
|
delete_on_timer=False,
|
@@ -854,8 +857,16 @@ class ColumnHeaders(tk.Canvas):
|
|
854
857
|
):
|
855
858
|
datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
|
856
859
|
canvasx = self.canvasx(event.x)
|
857
|
-
if self.event_over_dropdown(
|
858
|
-
c,
|
860
|
+
if self.event_over_dropdown(
|
861
|
+
c,
|
862
|
+
datacn,
|
863
|
+
event,
|
864
|
+
canvasx,
|
865
|
+
) or self.event_over_checkbox(
|
866
|
+
c,
|
867
|
+
datacn,
|
868
|
+
event,
|
869
|
+
canvasx,
|
859
870
|
):
|
860
871
|
self.open_cell(event)
|
861
872
|
else:
|
@@ -970,15 +981,15 @@ class ColumnHeaders(tk.Canvas):
|
|
970
981
|
qconf = self.MT.txt_measure_canvas.itemconfig
|
971
982
|
qbbox = self.MT.txt_measure_canvas.bbox
|
972
983
|
qtxtm = self.MT.txt_measure_canvas_text
|
984
|
+
qfont = self.PAR.ops.header_font
|
973
985
|
new_height = self.MT.min_header_height
|
974
986
|
default_header_height = self.MT.get_default_header_height()
|
975
987
|
self.fix_header()
|
976
988
|
if text is not None:
|
977
989
|
if text:
|
978
|
-
qconf(qtxtm, text=text)
|
990
|
+
qconf(qtxtm, text=text, font=qfont)
|
979
991
|
b = qbbox(qtxtm)
|
980
|
-
h
|
981
|
-
if h > new_height:
|
992
|
+
if (h := b[3] - b[1] + 5) > new_height:
|
982
993
|
new_height = h
|
983
994
|
else:
|
984
995
|
if self.MT.all_columns_displayed:
|
@@ -1002,7 +1013,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1002
1013
|
for datacn in iterable:
|
1003
1014
|
txt = self.MT.get_valid_cell_data_as_str(datarn, datacn, get_displayed=True)
|
1004
1015
|
if txt:
|
1005
|
-
qconf(qtxtm, text=txt)
|
1016
|
+
qconf(qtxtm, text=txt, font=qfont)
|
1006
1017
|
b = qbbox(qtxtm)
|
1007
1018
|
h = b[3] - b[1] + 5
|
1008
1019
|
else:
|
@@ -1014,7 +1025,7 @@ class ColumnHeaders(tk.Canvas):
|
|
1014
1025
|
if h > new_height:
|
1015
1026
|
new_height = h
|
1016
1027
|
space_bot = self.MT.get_space_bot(0)
|
1017
|
-
if new_height > space_bot:
|
1028
|
+
if new_height > space_bot and space_bot > self.MT.min_header_height:
|
1018
1029
|
new_height = space_bot
|
1019
1030
|
if not only_increase or (only_increase and new_height > self.current_height):
|
1020
1031
|
self.set_height(new_height, set_TL=True)
|
@@ -1612,14 +1623,13 @@ class ColumnHeaders(tk.Canvas):
|
|
1612
1623
|
) -> bool:
|
1613
1624
|
text = None
|
1614
1625
|
extra_func_key = "??"
|
1615
|
-
datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
|
1616
1626
|
if event is None or self.MT.event_opens_dropdown_or_checkbox(event):
|
1617
1627
|
if event is not None:
|
1618
1628
|
if hasattr(event, "keysym") and event.keysym == "Return":
|
1619
1629
|
extra_func_key = "Return"
|
1620
1630
|
elif hasattr(event, "keysym") and event.keysym == "F2":
|
1621
1631
|
extra_func_key = "F2"
|
1622
|
-
text = self.get_cell_data(datacn, none_to_empty_str=True, redirect_int=True)
|
1632
|
+
text = self.get_cell_data(self.MT.datacn(c), none_to_empty_str=True, redirect_int=True)
|
1623
1633
|
elif event is not None and (
|
1624
1634
|
(hasattr(event, "keysym") and event.keysym == "BackSpace") or event.keycode in (8, 855638143)
|
1625
1635
|
):
|
@@ -1669,9 +1679,8 @@ class ColumnHeaders(tk.Canvas):
|
|
1669
1679
|
y = 0
|
1670
1680
|
w = self.MT.col_positions[c + 1] - x
|
1671
1681
|
h = self.current_height + 1
|
1672
|
-
datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
|
1673
1682
|
if text is None:
|
1674
|
-
text = self.get_cell_data(datacn, none_to_empty_str=True, redirect_int=True)
|
1683
|
+
text = self.get_cell_data(self.MT.datacn(c), none_to_empty_str=True, redirect_int=True)
|
1675
1684
|
bg, fg = self.PAR.ops.header_bg, self.PAR.ops.header_fg
|
1676
1685
|
kwargs = {
|
1677
1686
|
"menu_kwargs": DotDict(
|
@@ -1684,12 +1693,12 @@ class ColumnHeaders(tk.Canvas):
|
|
1684
1693
|
}
|
1685
1694
|
),
|
1686
1695
|
"sheet_ops": self.PAR.ops,
|
1687
|
-
"border_color": self.PAR.ops.
|
1696
|
+
"border_color": self.PAR.ops.header_selected_columns_bg,
|
1688
1697
|
"text": text,
|
1689
1698
|
"state": state,
|
1690
1699
|
"width": w,
|
1691
1700
|
"height": h,
|
1692
|
-
"show_border":
|
1701
|
+
"show_border": True,
|
1693
1702
|
"bg": bg,
|
1694
1703
|
"fg": fg,
|
1695
1704
|
"align": self.get_cell_align(c),
|
@@ -1735,62 +1744,74 @@ class ColumnHeaders(tk.Canvas):
|
|
1735
1744
|
|
1736
1745
|
# displayed indexes
|
1737
1746
|
def text_editor_newline_binding(self, r=0, c=0, event: object = None, check_lines=True):
|
1738
|
-
if self.height_resizing_enabled:
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
self.
|
1747
|
+
if not self.height_resizing_enabled:
|
1748
|
+
return
|
1749
|
+
curr_height = self.text_editor.window.winfo_height()
|
1750
|
+
if curr_height < self.MT.min_header_height:
|
1751
|
+
return
|
1752
|
+
if (
|
1753
|
+
not check_lines
|
1754
|
+
or self.MT.get_lines_cell_height(
|
1755
|
+
self.text_editor.window.get_num_lines() + 1,
|
1756
|
+
font=self.text_editor.tktext.cget("font"),
|
1757
|
+
)
|
1758
|
+
> curr_height
|
1759
|
+
):
|
1760
|
+
new_height = curr_height + self.MT.header_xtra_lines_increment
|
1761
|
+
space_bot = self.MT.get_space_bot(0)
|
1762
|
+
if new_height > space_bot:
|
1763
|
+
new_height = space_bot
|
1764
|
+
if new_height != curr_height:
|
1765
|
+
self.text_editor.window.config(height=new_height)
|
1766
|
+
self.set_height(new_height, set_TL=True)
|
1767
|
+
if self.dropdown.open and self.dropdown.get_coords() == c:
|
1768
|
+
win_h, anchor = self.get_dropdown_height_anchor(c, new_height)
|
1769
|
+
self.coords(
|
1770
|
+
self.dropdown.canvas_id,
|
1771
|
+
self.MT.col_positions[c],
|
1772
|
+
new_height - 1,
|
1773
|
+
)
|
1774
|
+
self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
|
1763
1775
|
|
1764
|
-
def refresh_open_window_positions(self):
|
1776
|
+
def refresh_open_window_positions(self, zoom: Literal["in", "out"]):
|
1765
1777
|
if self.text_editor.open:
|
1766
1778
|
c = self.text_editor.column
|
1767
|
-
self.text_editor.window.config(
|
1779
|
+
self.text_editor.window.config(
|
1780
|
+
height=self.current_height,
|
1781
|
+
width=self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1,
|
1782
|
+
)
|
1783
|
+
self.text_editor.tktext.config(font=self.PAR.ops.header_font)
|
1768
1784
|
self.coords(
|
1769
1785
|
self.text_editor.canvas_id,
|
1770
|
-
0,
|
1771
1786
|
self.MT.col_positions[c],
|
1787
|
+
0,
|
1772
1788
|
)
|
1773
1789
|
if self.dropdown.open:
|
1790
|
+
if zoom == "in":
|
1791
|
+
self.dropdown.window.zoom_in()
|
1792
|
+
elif zoom == "out":
|
1793
|
+
self.dropdown.window.zoom_out()
|
1774
1794
|
c = self.dropdown.get_coords()
|
1775
1795
|
if self.text_editor.open:
|
1776
1796
|
text_editor_h = self.text_editor.window.winfo_height()
|
1777
1797
|
win_h, anchor = self.get_dropdown_height_anchor(c, text_editor_h)
|
1778
1798
|
else:
|
1779
|
-
text_editor_h = self.
|
1799
|
+
text_editor_h = self.current_height
|
1780
1800
|
anchor = self.itemcget(self.dropdown.canvas_id, "anchor")
|
1781
1801
|
# win_h = 0
|
1802
|
+
self.dropdown.window.config(width=self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1)
|
1782
1803
|
if anchor == "nw":
|
1783
1804
|
self.coords(
|
1784
1805
|
self.dropdown.canvas_id,
|
1785
|
-
|
1786
|
-
|
1806
|
+
self.MT.col_positions[c],
|
1807
|
+
text_editor_h - 1,
|
1787
1808
|
)
|
1788
1809
|
# self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
|
1789
1810
|
elif anchor == "sw":
|
1790
1811
|
self.coords(
|
1791
1812
|
self.dropdown.canvas_id,
|
1792
|
-
0,
|
1793
1813
|
self.MT.col_positions[c],
|
1814
|
+
0,
|
1794
1815
|
)
|
1795
1816
|
# self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
|
1796
1817
|
|
@@ -1888,42 +1909,39 @@ class ColumnHeaders(tk.Canvas):
|
|
1888
1909
|
modified_func(event)
|
1889
1910
|
dd_window.search_and_see(event)
|
1890
1911
|
|
1891
|
-
def open_dropdown_window(self, c,
|
1912
|
+
def open_dropdown_window(self, c, event: object = None):
|
1892
1913
|
self.hide_text_editor("Escape")
|
1893
|
-
|
1894
|
-
datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
|
1895
|
-
kwargs = self.get_cell_kwargs(datacn, key="dropdown")
|
1914
|
+
kwargs = self.get_cell_kwargs(self.MT.datacn(c), key="dropdown")
|
1896
1915
|
if kwargs["state"] == "normal":
|
1897
1916
|
if not self.open_text_editor(event=event, c=c, dropdown=True):
|
1898
1917
|
return
|
1899
1918
|
win_h, anchor = self.get_dropdown_height_anchor(c)
|
1919
|
+
win_w = self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1
|
1900
1920
|
ypos = self.current_height - 1
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
|
1905
|
-
|
1906
|
-
self.
|
1907
|
-
|
1908
|
-
|
1921
|
+
reset_kwargs = {
|
1922
|
+
"r": 0,
|
1923
|
+
"c": c,
|
1924
|
+
"width": win_w,
|
1925
|
+
"height": win_h,
|
1926
|
+
"font": self.PAR.ops.header_font,
|
1927
|
+
"ops": self.PAR.ops,
|
1928
|
+
"outline_color": self.PAR.ops.popup_menu_fg,
|
1929
|
+
"align": self.get_cell_align(c),
|
1930
|
+
"values": kwargs["values"],
|
1931
|
+
}
|
1932
|
+
if self.dropdown.window:
|
1933
|
+
self.dropdown.window.reset(**reset_kwargs)
|
1934
|
+
self.itemconfig(self.dropdown.canvas_id, state="normal")
|
1909
1935
|
self.coords(self.dropdown.canvas_id, self.MT.col_positions[c], ypos)
|
1910
1936
|
else:
|
1911
1937
|
self.dropdown.window = self.PAR.dropdown_class(
|
1912
|
-
self.
|
1913
|
-
|
1914
|
-
c,
|
1915
|
-
width=self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1,
|
1916
|
-
height=win_h,
|
1917
|
-
font=self.PAR.ops.header_font,
|
1918
|
-
ops=self.PAR.ops,
|
1919
|
-
outline_color=self.PAR.ops.popup_menu_fg,
|
1920
|
-
values=kwargs["values"],
|
1938
|
+
self.winfo_toplevel(),
|
1939
|
+
**reset_kwargs,
|
1940
|
+
single_index="c",
|
1921
1941
|
close_dropdown_window=self.close_dropdown_window,
|
1922
1942
|
search_function=kwargs["search_function"],
|
1923
1943
|
arrowkey_RIGHT=self.MT.arrowkey_RIGHT,
|
1924
1944
|
arrowkey_LEFT=self.MT.arrowkey_LEFT,
|
1925
|
-
align="w",
|
1926
|
-
single_index="c",
|
1927
1945
|
)
|
1928
1946
|
self.dropdown.canvas_id = self.create_window(
|
1929
1947
|
(self.MT.col_positions[c], ypos),
|
@@ -245,6 +245,12 @@ def is_iterable(o: object) -> bool:
|
|
245
245
|
return False
|
246
246
|
|
247
247
|
|
248
|
+
def int_x_iter(i: Iterator[int] | int) -> Iterator[int]:
|
249
|
+
if isinstance(i, int):
|
250
|
+
return (i,)
|
251
|
+
return i
|
252
|
+
|
253
|
+
|
248
254
|
def unpack(t: tuple[object] | tuple[Iterator[object]]) -> tuple[object]:
|
249
255
|
if not len(t):
|
250
256
|
return t
|
@@ -345,21 +351,27 @@ def get_seq_without_gaps_at_index(
|
|
345
351
|
return seq
|
346
352
|
|
347
353
|
|
348
|
-
def consecutive_chunks(seq: list[
|
349
|
-
if not seq:
|
350
|
-
yield seq
|
354
|
+
def consecutive_chunks(seq: list[int]) -> Generator[list[int]]:
|
351
355
|
start = 0
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
yield seq[start:end]
|
358
|
-
start = end
|
359
|
-
else:
|
356
|
+
for index, value in enumerate(seq, 1):
|
357
|
+
try:
|
358
|
+
if seq[index] > value + 1:
|
359
|
+
yield seq[start:(start := index)]
|
360
|
+
except Exception:
|
360
361
|
yield seq[start : len(seq)]
|
361
362
|
|
362
363
|
|
364
|
+
def consecutive_ranges(seq: Sequence[int]) -> Generator[tuple[int, int]]:
|
365
|
+
start = 0
|
366
|
+
for index, value in enumerate(seq, 1):
|
367
|
+
try:
|
368
|
+
if seq[index] > value + 1:
|
369
|
+
yield seq[start], seq[index - 1] + 1
|
370
|
+
start = index
|
371
|
+
except Exception:
|
372
|
+
yield seq[start], seq[-1] + 1
|
373
|
+
|
374
|
+
|
363
375
|
def is_contiguous(seq: list[int]) -> bool:
|
364
376
|
itr = iter(seq)
|
365
377
|
prev = next(itr)
|
@@ -1146,6 +1158,22 @@ def set_readonly(
|
|
1146
1158
|
return options
|
1147
1159
|
|
1148
1160
|
|
1161
|
+
def convert_align(align: str | None) -> str | None:
|
1162
|
+
if isinstance(align, str):
|
1163
|
+
a = align.lower()
|
1164
|
+
if a == "global":
|
1165
|
+
return None
|
1166
|
+
elif a in ("c", "center", "centre"):
|
1167
|
+
return "center"
|
1168
|
+
elif a in ("w", "west", "left"):
|
1169
|
+
return "w"
|
1170
|
+
elif a in ("e", "east", "right"):
|
1171
|
+
return "e"
|
1172
|
+
elif align is None:
|
1173
|
+
return None
|
1174
|
+
raise ValueError("Align must be one of the following values: c, center, w, west, left, e, east, right")
|
1175
|
+
|
1176
|
+
|
1149
1177
|
def set_align(
|
1150
1178
|
options: dict,
|
1151
1179
|
key: int | tuple[int, int],
|