tksheet 7.3.1__tar.gz → 7.3.3__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.
Files changed (25) hide show
  1. {tksheet-7.3.1/tksheet.egg-info → tksheet-7.3.3}/PKG-INFO +10 -11
  2. {tksheet-7.3.1 → tksheet-7.3.3}/README.md +8 -9
  3. {tksheet-7.3.1 → tksheet-7.3.3}/pyproject.toml +1 -1
  4. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/__init__.py +2 -2
  5. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/column_headers.py +22 -36
  6. tksheet-7.3.3/tksheet/find_window.py +251 -0
  7. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/formatters.py +1 -1
  8. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/functions.py +154 -45
  9. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/main_table.py +458 -284
  10. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/other_classes.py +6 -9
  11. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/row_index.py +23 -35
  12. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/sheet.py +75 -21
  13. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/sheet_options.py +16 -1
  14. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/text_editor.py +1 -1
  15. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/top_left_rectangle.py +1 -1
  16. {tksheet-7.3.1 → tksheet-7.3.3/tksheet.egg-info}/PKG-INFO +10 -11
  17. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet.egg-info/SOURCES.txt +2 -1
  18. {tksheet-7.3.1 → tksheet-7.3.3}/LICENSE.txt +0 -0
  19. {tksheet-7.3.1 → tksheet-7.3.3}/setup.cfg +0 -0
  20. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/colors.py +0 -0
  21. /tksheet-7.3.1/tksheet/vars.py → /tksheet-7.3.3/tksheet/constants.py +0 -0
  22. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/themes.py +0 -0
  23. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet/types.py +0 -0
  24. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet.egg-info/dependency_links.txt +0 -0
  25. {tksheet-7.3.1 → tksheet-7.3.3}/tksheet.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: tksheet
3
- Version: 7.3.1
3
+ Version: 7.3.3
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
@@ -95,22 +95,21 @@ This library is maintained with the help of **[others](https://github.com/ragard
95
95
 
96
96
  ## **Features**
97
97
 
98
- - Display and modify tabular data
99
- - Stores its display data as a Python list of lists, sublists being rows
100
- - Runs smoothly even with millions of rows/columns
101
- - Edit cells directly
98
+ - Smoothly display and modify tabular data
99
+ - [Edit cells directly](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
102
100
  - Cell values can potentially be [any class](https://github.com/ragardner/tksheet/wiki/Version-7#data-formatting), the default is any class with a `__str__` method
103
- - Drag and drop columns and rows
101
+ - [Drag and drop columns and rows](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
104
102
  - Multiple line header and index cells
105
- - Expand row heights and column widths
106
- - Change fonts and font size (not for individual cells)
107
- - Change any colors in the sheet
103
+ - [Expand row heights and column widths](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
104
+ - [Change fonts and font size (not for individual cells)](https://github.com/ragardner/tksheet/wiki/Version-7#text-font-and-alignment)
105
+ - [Change any colors in the sheet](https://github.com/ragardner/tksheet/wiki/Version-7#sheet-appearance)
108
106
  - [Treeview mode](https://github.com/ragardner/tksheet/wiki/Version-7#treeview-mode)
109
107
  - [Dropdown boxes](https://github.com/ragardner/tksheet/wiki/Version-7#dropdown-boxes)
110
108
  - [Check boxes](https://github.com/ragardner/tksheet/wiki/Version-7#check-boxes)
111
109
  - [Progress bars](https://github.com/ragardner/tksheet/wiki/Version-7#progress-bars)
112
110
  - [Hide rows and/or columns](https://github.com/ragardner/tksheet/wiki/Version-7#example-header-dropdown-boxes-and-row-filtering)
113
- - Left `"w"`, Center `"center"` or Right `"e"` text alignment for any cell/row/column
111
+ - [Left `"w"`, Center `"center"` or Right `"e"` text alignment for any cell/row/column](https://github.com/ragardner/tksheet/wiki/Version-7#text-font-and-alignment)
112
+ - [Optional built-in find window](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
114
113
 
115
114
  ```python
116
115
  """
@@ -52,22 +52,21 @@ This library is maintained with the help of **[others](https://github.com/ragard
52
52
 
53
53
  ## **Features**
54
54
 
55
- - Display and modify tabular data
56
- - Stores its display data as a Python list of lists, sublists being rows
57
- - Runs smoothly even with millions of rows/columns
58
- - Edit cells directly
55
+ - Smoothly display and modify tabular data
56
+ - [Edit cells directly](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
59
57
  - Cell values can potentially be [any class](https://github.com/ragardner/tksheet/wiki/Version-7#data-formatting), the default is any class with a `__str__` method
60
- - Drag and drop columns and rows
58
+ - [Drag and drop columns and rows](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
61
59
  - Multiple line header and index cells
62
- - Expand row heights and column widths
63
- - Change fonts and font size (not for individual cells)
64
- - Change any colors in the sheet
60
+ - [Expand row heights and column widths](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
61
+ - [Change fonts and font size (not for individual cells)](https://github.com/ragardner/tksheet/wiki/Version-7#text-font-and-alignment)
62
+ - [Change any colors in the sheet](https://github.com/ragardner/tksheet/wiki/Version-7#sheet-appearance)
65
63
  - [Treeview mode](https://github.com/ragardner/tksheet/wiki/Version-7#treeview-mode)
66
64
  - [Dropdown boxes](https://github.com/ragardner/tksheet/wiki/Version-7#dropdown-boxes)
67
65
  - [Check boxes](https://github.com/ragardner/tksheet/wiki/Version-7#check-boxes)
68
66
  - [Progress bars](https://github.com/ragardner/tksheet/wiki/Version-7#progress-bars)
69
67
  - [Hide rows and/or columns](https://github.com/ragardner/tksheet/wiki/Version-7#example-header-dropdown-boxes-and-row-filtering)
70
- - Left `"w"`, Center `"center"` or Right `"e"` text alignment for any cell/row/column
68
+ - [Left `"w"`, Center `"center"` or Right `"e"` text alignment for any cell/row/column](https://github.com/ragardner/tksheet/wiki/Version-7#text-font-and-alignment)
69
+ - [Optional built-in find window](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
71
70
 
72
71
  ```python
73
72
  """
@@ -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.3.1"
9
+ version = "7.3.3"
10
10
  authors = [{ name = "ragardner", email = "github@ragardner.simplelogin.com" }]
11
11
  requires-python = ">=3.8"
12
12
  license = {file = "LICENSE.txt"}
@@ -4,7 +4,7 @@
4
4
  tksheet - A Python tkinter table widget
5
5
  """
6
6
 
7
- __version__ = "7.3.1"
7
+ __version__ = "7.3.3"
8
8
 
9
9
  from .colors import (
10
10
  color_map,
@@ -96,7 +96,7 @@ from .themes import (
96
96
  theme_light_green,
97
97
  )
98
98
  from .top_left_rectangle import TopLeftRectangle
99
- from .vars import (
99
+ from .constants import (
100
100
  USER_OS,
101
101
  ctrl_key,
102
102
  emitted_events,
@@ -23,10 +23,19 @@ from typing import Literal
23
23
  from .colors import (
24
24
  color_map,
25
25
  )
26
+ from .constants import (
27
+ USER_OS,
28
+ rc_binding,
29
+ text_editor_close_bindings,
30
+ text_editor_newline_bindings,
31
+ text_editor_to_unbind,
32
+ )
26
33
  from .formatters import is_bool_like, try_to_bool
27
34
  from .functions import (
28
35
  consecutive_ranges,
29
36
  event_dict,
37
+ event_has_char_key,
38
+ event_opens_dropdown_or_checkbox,
30
39
  get_n2a,
31
40
  int_x_tuple,
32
41
  is_contiguous,
@@ -47,14 +56,6 @@ from .text_editor import (
47
56
  from .types import (
48
57
  AnyIter,
49
58
  )
50
- from .vars import (
51
- USER_OS,
52
- rc_binding,
53
- symbols_set,
54
- text_editor_close_bindings,
55
- text_editor_newline_bindings,
56
- text_editor_to_unbind,
57
- )
58
59
 
59
60
 
60
61
  class ColumnHeaders(tk.Canvas):
@@ -1672,8 +1673,8 @@ class ColumnHeaders(tk.Canvas):
1672
1673
 
1673
1674
  def get_redraw_selections(self, startc: int, endc: int) -> dict[str, set[int]]:
1674
1675
  d = defaultdict(set)
1675
- for item, box in self.MT.get_selection_items():
1676
- r1, c1, r2, c2 = box.coords
1676
+ for _, box in self.MT.get_selection_items():
1677
+ _, c1, _, c2 = box.coords
1677
1678
  for c in range(startc, endc):
1678
1679
  if c1 <= c and c2 > c:
1679
1680
  d[box.type_ if box.type_ != "rows" else "cells"].add(c)
@@ -1689,7 +1690,7 @@ class ColumnHeaders(tk.Canvas):
1689
1690
  if self.get_cell_kwargs(datacn, key="readonly"):
1690
1691
  return
1691
1692
  elif self.get_cell_kwargs(datacn, key="dropdown") or self.get_cell_kwargs(datacn, key="checkbox"):
1692
- if self.MT.event_opens_dropdown_or_checkbox(event):
1693
+ if event_opens_dropdown_or_checkbox(event):
1693
1694
  if self.get_cell_kwargs(datacn, key="dropdown"):
1694
1695
  self.open_dropdown_window(c, event=event)
1695
1696
  elif self.get_cell_kwargs(datacn, key="checkbox"):
@@ -1715,28 +1716,16 @@ class ColumnHeaders(tk.Canvas):
1715
1716
  state: str = "normal",
1716
1717
  dropdown: bool = False,
1717
1718
  ) -> bool:
1718
- text = None
1719
+ text = f"{self.get_cell_data(self.MT.datacn(c), none_to_empty_str=True, redirect_int=True)}"
1719
1720
  extra_func_key = "??"
1720
- if event is None or self.MT.event_opens_dropdown_or_checkbox(event):
1721
- if event is not None:
1722
- if hasattr(event, "keysym") and event.keysym == "Return":
1723
- extra_func_key = "Return"
1724
- elif hasattr(event, "keysym") and event.keysym == "F2":
1725
- extra_func_key = "F2"
1726
- text = self.get_cell_data(self.MT.datacn(c), none_to_empty_str=True, redirect_int=True)
1727
- elif event is not None and (
1728
- (hasattr(event, "keysym") and event.keysym == "BackSpace") or event.keycode in (8, 855638143)
1729
- ):
1730
- extra_func_key = "BackSpace"
1731
- text = ""
1732
- elif event is not None and (
1733
- (hasattr(event, "char") and event.char.isalpha())
1734
- or (hasattr(event, "char") and event.char.isdigit())
1735
- or (hasattr(event, "char") and event.char in symbols_set)
1736
- ):
1737
- extra_func_key = event.char
1738
- text = event.char
1739
- else:
1721
+ if event_opens_dropdown_or_checkbox(event):
1722
+ if hasattr(event, "keysym") and event.keysym in ("Return", "F2", "BackSpace"):
1723
+ extra_func_key = event.keysym
1724
+ if event.keysym == "BackSpace":
1725
+ text = ""
1726
+ elif event_has_char_key(event):
1727
+ extra_func_key = text = event.char
1728
+ elif event is not None:
1740
1729
  return False
1741
1730
  if self.extra_begin_edit_cell_func:
1742
1731
  try:
@@ -1758,14 +1747,13 @@ class ColumnHeaders(tk.Canvas):
1758
1747
  return False
1759
1748
  else:
1760
1749
  text = text if isinstance(text, str) else f"{text}"
1761
- text = "" if text is None else text
1762
1750
  if self.PAR.ops.cell_auto_resize_enabled:
1763
1751
  if self.height_resizing_enabled:
1764
1752
  self.set_height_of_header_to_text(text)
1765
1753
  self.set_col_width_run_binding(c)
1766
1754
  if self.text_editor.open and c == self.text_editor.column:
1767
1755
  self.text_editor.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
1768
- return
1756
+ return False
1769
1757
  self.hide_text_editor()
1770
1758
  if not self.MT.see(r=0, c=c, keep_yscroll=True, check_cell_visibility=True):
1771
1759
  self.MT.refresh()
@@ -1773,8 +1761,6 @@ class ColumnHeaders(tk.Canvas):
1773
1761
  y = 0
1774
1762
  w = self.MT.col_positions[c + 1] - x
1775
1763
  h = self.current_height + 1
1776
- if text is None:
1777
- text = self.get_cell_data(self.MT.datacn(c), none_to_empty_str=True, redirect_int=True)
1778
1764
  kwargs = {
1779
1765
  "menu_kwargs": DotDict(
1780
1766
  {
@@ -0,0 +1,251 @@
1
+ from __future__ import annotations
2
+
3
+ import tkinter as tk
4
+ from collections.abc import (
5
+ Callable,
6
+ )
7
+ from typing import Literal
8
+
9
+ from .other_classes import (
10
+ DotDict,
11
+ )
12
+ from .constants import (
13
+ ctrl_key,
14
+ rc_binding,
15
+ )
16
+ from .functions import (
17
+ recursive_bind,
18
+ )
19
+
20
+
21
+ class FindWindowTkText(tk.Text):
22
+ def __init__(
23
+ self,
24
+ parent: tk.Misc,
25
+ ) -> None:
26
+ super().__init__(
27
+ parent,
28
+ spacing1=0,
29
+ spacing2=1,
30
+ spacing3=0,
31
+ bd=0,
32
+ highlightthickness=0,
33
+ undo=True,
34
+ maxundo=30,
35
+ )
36
+ self.parent = parent
37
+ self.rc_popup_menu = tk.Menu(self, tearoff=0)
38
+ self.bind("<1>", lambda event: self.focus_set())
39
+ self.bind(rc_binding, self.rc)
40
+ self.bind(f"<{ctrl_key}-a>", self.select_all)
41
+ self.bind(f"<{ctrl_key}-A>", self.select_all)
42
+ self.bind("<Delete>", self.delete_key)
43
+
44
+ def reset(
45
+ self,
46
+ menu_kwargs: dict,
47
+ sheet_ops: dict,
48
+ font: tuple,
49
+ bg: str,
50
+ fg: str,
51
+ select_bg: str,
52
+ select_fg: str,
53
+ ) -> None:
54
+ self.config(
55
+ font=font,
56
+ background=bg,
57
+ foreground=fg,
58
+ insertbackground=fg,
59
+ selectbackground=select_bg,
60
+ selectforeground=select_fg,
61
+ )
62
+ self.editor_del_key = sheet_ops.editor_del_key
63
+ self.rc_popup_menu.delete(0, "end")
64
+ self.rc_popup_menu.add_command(
65
+ label=sheet_ops.select_all_label,
66
+ accelerator=sheet_ops.select_all_accelerator,
67
+ command=self.select_all,
68
+ **menu_kwargs,
69
+ )
70
+ self.rc_popup_menu.add_command(
71
+ label=sheet_ops.cut_label,
72
+ accelerator=sheet_ops.cut_accelerator,
73
+ command=self.cut,
74
+ **menu_kwargs,
75
+ )
76
+ self.rc_popup_menu.add_command(
77
+ label=sheet_ops.copy_label,
78
+ accelerator=sheet_ops.copy_accelerator,
79
+ command=self.copy,
80
+ **menu_kwargs,
81
+ )
82
+ self.rc_popup_menu.add_command(
83
+ label=sheet_ops.paste_label,
84
+ accelerator=sheet_ops.paste_accelerator,
85
+ command=self.paste,
86
+ **menu_kwargs,
87
+ )
88
+ self.rc_popup_menu.add_command(
89
+ label=sheet_ops.undo_label,
90
+ accelerator=sheet_ops.undo_accelerator,
91
+ command=self.undo,
92
+ **menu_kwargs,
93
+ )
94
+
95
+ def rc(self, event: object) -> None:
96
+ self.focus_set()
97
+ self.rc_popup_menu.tk_popup(event.x_root, event.y_root)
98
+
99
+ def delete_key(self, event: object = None) -> None:
100
+ if self.editor_del_key == "forward":
101
+ return
102
+ elif not self.editor_del_key:
103
+ return "break"
104
+ elif self.editor_del_key == "backward":
105
+ if self.tag_ranges("sel"):
106
+ return
107
+ if self.index("insert") == "1.0":
108
+ return "break"
109
+ self.delete("insert-1c")
110
+ return "break"
111
+
112
+ def select_all(self, event: object = None) -> Literal["break"]:
113
+ self.tag_add(tk.SEL, "1.0", tk.END)
114
+ self.mark_set(tk.INSERT, tk.END)
115
+ # self.see(tk.INSERT)
116
+ return "break"
117
+
118
+ def cut(self, event: object = None) -> Literal["break"]:
119
+ self.event_generate(f"<{ctrl_key}-x>")
120
+ self.event_generate("<KeyRelease>")
121
+ return "break"
122
+
123
+ def copy(self, event: object = None) -> Literal["break"]:
124
+ self.event_generate(f"<{ctrl_key}-c>")
125
+ return "break"
126
+
127
+ def paste(self, event: object = None) -> Literal["break"]:
128
+ self.event_generate(f"<{ctrl_key}-v>")
129
+ self.event_generate("<KeyRelease>")
130
+ return "break"
131
+
132
+ def undo(self, event: object = None) -> Literal["break"]:
133
+ self.event_generate(f"<{ctrl_key}-z>")
134
+ self.event_generate("<KeyRelease>")
135
+ return "break"
136
+
137
+
138
+ class FindWindow(tk.Frame):
139
+ def __init__(
140
+ self,
141
+ parent: tk.Misc,
142
+ find_next_func: Callable,
143
+ find_prev_func: Callable,
144
+ close_func: Callable,
145
+ ) -> None:
146
+ super().__init__(
147
+ parent,
148
+ width=0,
149
+ height=0,
150
+ bd=0,
151
+ )
152
+ self.grid_columnconfigure(0, weight=1)
153
+ self.grid_rowconfigure(0, weight=1)
154
+ self.grid_propagate(False)
155
+ self.parent = parent
156
+ self.tktext = FindWindowTkText(self)
157
+ self.tktext.grid(row=0, column=0, sticky="nswe")
158
+ self.bg = None
159
+ self.fg = None
160
+
161
+ self.find_previous_arrow = tk.Label(self, text="▲", cursor="hand2", highlightthickness=1)
162
+ self.find_previous_arrow.bind("<Button-1>", find_prev_func)
163
+ self.find_previous_arrow.grid(row=0, column=1)
164
+
165
+ self.find_next_arrow = tk.Label(self, text="▼", cursor="hand2", highlightthickness=1)
166
+ self.find_next_arrow.bind("<Button-1>", find_next_func)
167
+ self.find_next_arrow.grid(row=0, column=2)
168
+
169
+ self.find_in_selection = False
170
+ self.in_selection = tk.Label(self, text="🔎", cursor="hand2", highlightthickness=1)
171
+ self.in_selection.bind("<Button-1>", self.toggle_in_selection)
172
+ self.in_selection.grid(row=0, column=3)
173
+
174
+ self.close = tk.Label(self, text="✕", cursor="hand2", highlightthickness=1)
175
+ self.close.bind("<Button-1>", close_func)
176
+ self.close.grid(row=0, column=4)
177
+
178
+ for widget in (self.find_previous_arrow, self.find_next_arrow, self.in_selection, self.close):
179
+ widget.bind("<Enter>", lambda w, widget=widget: self.enter_label(widget=widget))
180
+ widget.bind("<Leave>", lambda w, widget=widget: self.leave_label(widget=widget))
181
+
182
+ for b in ("Option", "Alt"):
183
+ for c in ("l", "L"):
184
+ recursive_bind(self, f"<{b}-{c}>", self.toggle_in_selection)
185
+
186
+ def enter_label(self, widget: tk.Misc) -> None:
187
+ widget.config(
188
+ highlightbackground=self.fg,
189
+ highlightcolor=self.fg,
190
+ )
191
+
192
+ def leave_label(self, widget: tk.Misc) -> None:
193
+ if widget == self.in_selection and self.find_in_selection:
194
+ return
195
+ widget.config(
196
+ highlightbackground=self.bg,
197
+ highlightcolor=self.fg,
198
+ )
199
+
200
+ def toggle_in_selection(self, event: tk.Misc) -> None:
201
+ self.find_in_selection = not self.find_in_selection
202
+ self.enter_label(self.in_selection)
203
+ self.leave_label(self.in_selection)
204
+
205
+ def get(self) -> str:
206
+ return self.tktext.get("1.0", "end-1c")
207
+
208
+ def get_num_lines(self) -> int:
209
+ return int(self.tktext.index("end-1c").split(".")[0])
210
+
211
+ def set_text(self, text: str = "") -> None:
212
+ self.tktext.delete(1.0, "end")
213
+ self.tktext.insert(1.0, text)
214
+
215
+ def reset(
216
+ self,
217
+ border_color: str,
218
+ menu_kwargs: DotDict,
219
+ sheet_ops: DotDict,
220
+ bg: str,
221
+ fg: str,
222
+ select_bg: str,
223
+ select_fg: str,
224
+ ) -> None:
225
+ self.bg = bg
226
+ self.fg = fg
227
+ self.tktext.reset(
228
+ menu_kwargs=menu_kwargs,
229
+ sheet_ops=sheet_ops,
230
+ font=menu_kwargs.font,
231
+ bg=bg,
232
+ fg=fg,
233
+ select_bg=select_bg,
234
+ select_fg=select_fg,
235
+ )
236
+ for widget in (self.find_previous_arrow, self.find_next_arrow, self.in_selection, self.close):
237
+ widget.config(
238
+ font=menu_kwargs.font,
239
+ bg=bg,
240
+ fg=fg,
241
+ highlightbackground=bg,
242
+ highlightcolor=fg,
243
+ )
244
+ if self.find_in_selection:
245
+ self.enter_label(self.in_selection)
246
+ self.config(
247
+ background=bg,
248
+ highlightbackground=border_color,
249
+ highlightcolor=border_color,
250
+ highlightthickness=1,
251
+ )
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from collections.abc import Callable
4
4
 
5
- from .vars import falsy, nonelike, truthy
5
+ from .constants import falsy, nonelike, truthy
6
6
 
7
7
 
8
8
  def is_none_like(o: object) -> bool: