tksheet 7.5.5__py3-none-any.whl → 7.5.7__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/tooltip.py ADDED
@@ -0,0 +1,335 @@
1
+ from __future__ import annotations
2
+
3
+ import tkinter as tk
4
+ from tkinter import ttk
5
+ from typing import Any, Literal
6
+
7
+ from .constants import ctrl_key, rc_binding
8
+
9
+
10
+ class TooltipTkText(tk.Text):
11
+ """Custom Text widget for the Tooltip class."""
12
+
13
+ def __init__(
14
+ self,
15
+ parent: tk.Misc,
16
+ ) -> None:
17
+ super().__init__(
18
+ parent,
19
+ spacing1=0,
20
+ spacing2=1,
21
+ spacing3=0,
22
+ bd=0,
23
+ highlightthickness=0,
24
+ undo=True,
25
+ maxundo=30,
26
+ )
27
+ self.parent = parent
28
+ self.rc_popup_menu = tk.Menu(self, tearoff=0)
29
+ self.bind("<1>", lambda event: self.focus_set())
30
+ self.bind(rc_binding, self.rc)
31
+ self.bind(f"<{ctrl_key}-a>", self.select_all)
32
+ self.bind(f"<{ctrl_key}-A>", self.select_all)
33
+ self.bind("<Delete>", self.delete_key)
34
+
35
+ def reset(
36
+ self,
37
+ menu_kwargs: dict,
38
+ sheet_ops: dict,
39
+ bg: str,
40
+ fg: str,
41
+ select_bg: str,
42
+ select_fg: str,
43
+ text: str,
44
+ readonly: bool,
45
+ ) -> None:
46
+ """Reset the text widget's appearance and menu options."""
47
+ self.config(
48
+ font=sheet_ops.table_font,
49
+ background=bg,
50
+ foreground=fg,
51
+ insertbackground=fg,
52
+ selectbackground=select_bg,
53
+ selectforeground=select_fg,
54
+ )
55
+ self.editor_del_key = sheet_ops.editor_del_key
56
+ self.config(state="normal")
57
+ self.delete(1.0, "end")
58
+ self.insert(1.0, text)
59
+ self.edit_reset()
60
+ self.rc_popup_menu.delete(0, "end")
61
+ self.rc_popup_menu.add_command(
62
+ label=sheet_ops.select_all_label,
63
+ accelerator=sheet_ops.select_all_accelerator,
64
+ image=sheet_ops.select_all_image,
65
+ compound=sheet_ops.select_all_compound,
66
+ command=self.select_all,
67
+ **menu_kwargs,
68
+ )
69
+ if not readonly:
70
+ self.rc_popup_menu.add_command(
71
+ label=sheet_ops.cut_label,
72
+ accelerator=sheet_ops.cut_accelerator,
73
+ image=sheet_ops.cut_image,
74
+ compound=sheet_ops.cut_compound,
75
+ command=self.cut,
76
+ **menu_kwargs,
77
+ )
78
+ self.rc_popup_menu.add_command(
79
+ label=sheet_ops.copy_label,
80
+ accelerator=sheet_ops.copy_accelerator,
81
+ image=sheet_ops.copy_image,
82
+ compound=sheet_ops.copy_compound,
83
+ command=self.copy,
84
+ **menu_kwargs,
85
+ )
86
+ if not readonly:
87
+ self.rc_popup_menu.add_command(
88
+ label=sheet_ops.paste_label,
89
+ accelerator=sheet_ops.paste_accelerator,
90
+ image=sheet_ops.paste_image,
91
+ compound=sheet_ops.paste_compound,
92
+ command=self.paste,
93
+ **menu_kwargs,
94
+ )
95
+ self.rc_popup_menu.add_command(
96
+ label=sheet_ops.undo_label,
97
+ accelerator=sheet_ops.undo_accelerator,
98
+ image=sheet_ops.undo_image,
99
+ compound=sheet_ops.undo_compound,
100
+ command=self.undo,
101
+ **menu_kwargs,
102
+ )
103
+ self.rc_popup_menu.add_command(
104
+ label=sheet_ops.redo_label,
105
+ accelerator=sheet_ops.redo_accelerator,
106
+ image=sheet_ops.redo_image,
107
+ compound=sheet_ops.redo_compound,
108
+ command=self.redo,
109
+ **menu_kwargs,
110
+ )
111
+
112
+ def rc(self, event: Any) -> None:
113
+ """Show the right-click popup menu."""
114
+ self.rc_popup_menu.tk_popup(event.x_root, event.y_root)
115
+ self.focus_set()
116
+
117
+ def delete_key(self, event: Any = None) -> None:
118
+ """Handle the Delete key based on editor configuration."""
119
+ if self.editor_del_key == "forward":
120
+ return
121
+ elif not self.editor_del_key:
122
+ return "break"
123
+ elif self.editor_del_key == "backward":
124
+ if self.tag_ranges("sel"):
125
+ return
126
+ if self.index("insert") == "1.0":
127
+ return "break"
128
+ self.delete("insert-1c")
129
+ return "break"
130
+
131
+ def select_all(self, event: Any = None) -> Literal["break"]:
132
+ """Select all text in the widget."""
133
+ self.tag_add(tk.SEL, "1.0", "end-1c")
134
+ self.mark_set(tk.INSERT, "end-1c")
135
+ return "break"
136
+
137
+ def cut(self, event: Any = None) -> Literal["break"]:
138
+ """Cut selected text."""
139
+ self.event_generate(f"<{ctrl_key}-x>")
140
+ self.event_generate("<KeyRelease>")
141
+ return "break"
142
+
143
+ def copy(self, event: Any = None) -> Literal["break"]:
144
+ """Copy selected text."""
145
+ self.event_generate(f"<{ctrl_key}-c>")
146
+ return "break"
147
+
148
+ def paste(self, event: Any = None) -> Literal["break"]:
149
+ """Paste text from clipboard."""
150
+ self.event_generate(f"<{ctrl_key}-v>")
151
+ self.event_generate("<KeyRelease>")
152
+ return "break"
153
+
154
+ def undo(self, event: Any = None) -> Literal["break"]:
155
+ """Undo the last action."""
156
+ self.event_generate(f"<{ctrl_key}-z>")
157
+ self.event_generate("<KeyRelease>")
158
+ return "break"
159
+
160
+ def redo(self, event: Any = None) -> Literal["break"]:
161
+ self.event_generate(f"<{ctrl_key}-Shift-z>")
162
+ self.event_generate("<KeyRelease>")
163
+ return "break"
164
+
165
+
166
+ class Tooltip(tk.Toplevel):
167
+ def __init__(
168
+ self,
169
+ parent: tk.Misc,
170
+ sheet_ops: dict,
171
+ menu_kwargs: dict,
172
+ bg: str,
173
+ fg: str,
174
+ select_bg: str,
175
+ select_fg: str,
176
+ scrollbar_style: str,
177
+ ) -> None:
178
+ super().__init__(parent)
179
+ self.withdraw() # Hide until positioned
180
+ self.overrideredirect(True) # Borderless window
181
+ self.cell_readonly = True
182
+ self.note_readonly = True
183
+
184
+ # Store parameters
185
+ self.sheet_ops = sheet_ops
186
+ self.menu_kwargs = menu_kwargs
187
+ self.font = sheet_ops.table_font
188
+ self.bg = bg
189
+ self.fg = fg
190
+ self.select_bg = select_bg
191
+ self.select_fg = select_fg
192
+ self.row = 0
193
+ self.col = 0
194
+
195
+ # Create border frame for visual distinction
196
+ self.border_frame = tk.Frame(self, background=bg)
197
+ self.border_frame.pack(fill="both", expand=True, padx=1, pady=1)
198
+
199
+ # Create notebook, but don’t pack it yet
200
+ self.notebook = ttk.Notebook(self.border_frame)
201
+
202
+ # Content frame as child of border_frame
203
+ self.content_frame = ttk.Frame(self.border_frame)
204
+ self.content_text = TooltipTkText(self.content_frame)
205
+ self.content_scrollbar = ttk.Scrollbar(self.content_frame, orient="vertical", style=scrollbar_style)
206
+ self.content_scrollbar.pack(side="right", fill="y")
207
+ self.content_text.pack(side="left", fill="both", expand=True)
208
+ self.content_scrollbar.configure(command=self.content_text.yview)
209
+ self.content_text.configure(yscrollcommand=self.content_scrollbar.set)
210
+
211
+ # Note frame as child of border_frame
212
+ self.note_frame = ttk.Frame(self.border_frame)
213
+ self.note_text = TooltipTkText(self.note_frame)
214
+ self.note_scrollbar = ttk.Scrollbar(self.note_frame, orient="vertical", style=scrollbar_style)
215
+ self.note_scrollbar.pack(side="right", fill="y")
216
+ self.note_text.pack(side="left", fill="both", expand=True)
217
+ self.note_scrollbar.configure(command=self.note_text.yview)
218
+ self.note_text.configure(yscrollcommand=self.note_scrollbar.set)
219
+
220
+ def setup_note_only_mode(self):
221
+ """Configure the tooltip to show only the note text widget."""
222
+ self.notebook.pack_forget() # Remove notebook from layout
223
+ for tab in self.notebook.tabs(): # Clear all tabs to free the frames
224
+ self.notebook.forget(tab)
225
+ self.content_frame.pack_forget() # Ensure content_frame is not directly packed
226
+ self.note_frame.pack(fill="both", expand=True) # Show note_frame directly
227
+
228
+ def setup_single_text_mode(self):
229
+ """Configure the tooltip to show only the content text widget."""
230
+ self.notebook.pack_forget() # Remove notebook from layout
231
+ for tab in self.notebook.tabs(): # Clear all tabs
232
+ self.notebook.forget(tab)
233
+ self.note_frame.pack_forget() # Ensure note_frame is not directly packed
234
+ self.content_frame.pack(fill="both", expand=True) # Show content_frame directly
235
+
236
+ def setup_notebook_mode(self):
237
+ """Configure the tooltip to show a notebook with Cell and Note tabs."""
238
+ self.content_frame.pack_forget() # Ensure content_frame is not directly packed
239
+ self.note_frame.pack_forget() # Ensure note_frame is not directly packed
240
+ self.notebook.add(self.content_frame, text="Cell") # Add content tab
241
+ self.notebook.add(self.note_frame, text="Note") # Add note tab
242
+ self.notebook.pack(fill="both", expand=True) # Show notebook
243
+ self.notebook.select(0) # Select the "Cell" tab by default
244
+
245
+ def reset(
246
+ self,
247
+ text: str,
248
+ cell_readonly: bool,
249
+ note: str | None,
250
+ note_readonly: bool,
251
+ row: int,
252
+ col: int,
253
+ menu_kwargs: dict,
254
+ bg: str,
255
+ fg: str,
256
+ select_bg: str,
257
+ select_fg: str,
258
+ user_can_create_notes: bool,
259
+ note_only: bool,
260
+ width: int,
261
+ height: int,
262
+ ) -> None:
263
+ self.cell_readonly = cell_readonly
264
+ self.note_readonly = note_readonly
265
+ self.menu_kwargs = menu_kwargs
266
+ self.font = self.sheet_ops.table_font
267
+ self.bg = bg
268
+ self.fg = fg
269
+ self.select_bg = select_bg
270
+ self.select_fg = select_fg
271
+ self.row = row
272
+ self.col = col
273
+ self.config(bg=self.sheet_ops.table_selected_box_cells_fg)
274
+ self.border_frame.config(background=bg)
275
+ self.content_text.configure(
276
+ wrap="word",
277
+ width=30,
278
+ height=5,
279
+ state="disabled" if cell_readonly else "normal",
280
+ )
281
+ kws = {
282
+ "menu_kwargs": menu_kwargs,
283
+ "sheet_ops": self.sheet_ops,
284
+ "bg": bg,
285
+ "fg": fg,
286
+ "select_bg": select_bg,
287
+ "select_fg": select_fg,
288
+ }
289
+ self.content_text.reset(**kws, text=text, readonly=cell_readonly)
290
+ self.content_text.configure(state="disabled" if cell_readonly else "normal")
291
+ self.note_text.configure(
292
+ wrap="word",
293
+ width=30,
294
+ height=5,
295
+ )
296
+ self.note_text.reset(**kws, text="" if note is None else note, readonly=note_readonly)
297
+ self.note_text.configure(state="disabled" if note_readonly else "normal")
298
+ # Set up UI based on condition
299
+ if note_only:
300
+ self.setup_note_only_mode()
301
+ elif note is None and not user_can_create_notes:
302
+ self.setup_single_text_mode()
303
+ else:
304
+ self.setup_notebook_mode()
305
+ self.adjust_size(width, height)
306
+
307
+ def adjust_size(self, width, height) -> None:
308
+ """Adjust tooltip size to given dimensions."""
309
+ self.update_idletasks()
310
+ self.geometry(f"{width}x{height}")
311
+
312
+ def set_position(self, x_root: int, y_root: int) -> None:
313
+ """Position tooltip near the cell, avoiding screen edges."""
314
+ self.update_idletasks()
315
+ screen_width = self.winfo_screenwidth()
316
+ screen_height = self.winfo_screenheight()
317
+ width = self.winfo_width()
318
+ height = self.winfo_height()
319
+
320
+ # Adjust position to avoid screen edges
321
+ x = min(x_root, screen_width - width)
322
+ y = min(y_root, screen_height - height)
323
+ self.geometry(f"+{x}+{y}")
324
+ self.deiconify()
325
+
326
+ def get(self) -> tuple[int, int, str, str]:
327
+ return (
328
+ self.row,
329
+ self.col,
330
+ self.content_text.get("1.0", "end-1c"),
331
+ self.note_text.get("1.0", "end-1c"),
332
+ )
333
+
334
+ def destroy(self) -> None:
335
+ super().destroy()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tksheet
3
- Version: 7.5.5
3
+ Version: 7.5.7
4
4
  Summary: Tkinter table / sheet and treeview widget
5
5
  Author-email: ragardner <github@ragardner.simplelogin.com>
6
6
  License: Copyright (c) 2019 ragardner and open source contributors
@@ -0,0 +1,24 @@
1
+ tksheet/__init__.py,sha256=vNYNahxYlUHr2qV4kIpNVoZMDpCTWetLSBK0t4le_5o,2532
2
+ tksheet/colors.py,sha256=dHhmdFuQDlwohDHsAfT9VdrKoSl_R33L72a3HCin5zo,51591
3
+ tksheet/column_headers.py,sha256=5hwloDxaBO2wf_3qJbDDJWX8I8rKx-WPwv0UPWQ9xnk,110618
4
+ tksheet/constants.py,sha256=4cpU_PmOgN0isBVPWwCwBwqD8Fxnu4HJgDSSjfxjiPo,25467
5
+ tksheet/find_window.py,sha256=aV2U-IDFL6xNRhF4VomdrXEML4qw6QBqlfrVskuiTNY,20954
6
+ tksheet/formatters.py,sha256=r2vjgmKs_xWBYlfqVhPPNKQc67zCawOIl4dp4XAEzYg,10182
7
+ tksheet/functions.py,sha256=8S5u8GXl-uHxsRfGqG5Vt5ec7nOql7QczvTWSNuoRPg,56109
8
+ tksheet/main_table.py,sha256=5pdbQo245ahAXuJpsSNQEkPJHjJ7ETX1yNXdXrL-b7Q,367497
9
+ tksheet/menus.py,sha256=sRHZRgnYWddBtlzvbyWFSN2cVhlmUWyA9zf4vpqun7I,19431
10
+ tksheet/other_classes.py,sha256=6LpexHAxj23ZweuL3a4yCcdMSj_iXP38S7WRNQAehe0,18354
11
+ tksheet/row_index.py,sha256=-B-Fqz-HueJSsygKFFtcwrLUMe-O9MSeemaiCtVvfCo,146992
12
+ tksheet/sheet.py,sha256=i3h1FBko5dAdlWcv57WoP8e2NorRXk2eC_kACYaLK1Q,271847
13
+ tksheet/sheet_options.py,sha256=dhHY4jUULGXH2b_VOjoAfKXm3PAz7QL5CrVnHA0byho,14697
14
+ tksheet/sorting.py,sha256=zcZPpRtP1h_xJGtGkG3E43H7deKQFnh9cMwZ1B2-aGc,17502
15
+ tksheet/text_editor.py,sha256=Ksz4kT7TrCIzDhRZK9EM54M7R_5CvrwC1aeTrUPNOTg,8391
16
+ tksheet/themes.py,sha256=kUUCUmvgu8vUlzfVNk9a3BEbeBcU3asNwPB_u-OejCY,18471
17
+ tksheet/tksheet_types.py,sha256=qthH565jq60QCAeczvIWttIa4X5rFfLWPSwWBMDPilw,4611
18
+ tksheet/tooltip.py,sha256=TTWk3HW5Sltamish9GCnAECwZLa9Rm6QC8-RCDDtQnE,12374
19
+ tksheet/top_left_rectangle.py,sha256=A4wWL8PFl57Pn2Ek71rASCE1-bW844cTl7bgt4tLWzI,8499
20
+ tksheet-7.5.7.dist-info/licenses/LICENSE.txt,sha256=n1UvJHBr-AYNOf6ExICDsEggh9R7U4V4m_gH7FD-y-o,2305
21
+ tksheet-7.5.7.dist-info/METADATA,sha256=2n-VXhCSwYtl-7EZHyVGXXKyc4Jyh6R-tdlemz3QiuY,9474
22
+ tksheet-7.5.7.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
23
+ tksheet-7.5.7.dist-info/top_level.txt,sha256=my61PXCcck_HHAc9cq3NAlyAr3A3FXxCy9gptEOaCN8,8
24
+ tksheet-7.5.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,22 +0,0 @@
1
- tksheet/__init__.py,sha256=yXPme5a60Uus2oMIIqxg48ULgXvAvzZ2Mfjc2jesjCg,2532
2
- tksheet/colors.py,sha256=dHhmdFuQDlwohDHsAfT9VdrKoSl_R33L72a3HCin5zo,51591
3
- tksheet/column_headers.py,sha256=LioLw6JPuSqRD4E2b5EVfeEtz1Kja7N3ad7DdSf8HFs,103401
4
- tksheet/constants.py,sha256=f-w31-cmBt2PNcCYWYnpWgi7vNzqpFqJKqZoE9HXlRs,25454
5
- tksheet/find_window.py,sha256=6WMoCZcUbSLwIQNui4VwXfXhP9qtRp6-NE7UlwIaU2M,20929
6
- tksheet/formatters.py,sha256=DGcRiMsDJnySNpQcjfiX84oJ7TmOSMdU6u9injIhA4g,10095
7
- tksheet/functions.py,sha256=gonxCkLi6S9OeeAbf3bDeOJm3p3j447tjP9iXW9wCE8,53822
8
- tksheet/main_table.py,sha256=gFJCJJEiuN46ZyuQDxoP3UEx5ihCXD3lK5xldQcHtBU,378985
9
- tksheet/other_classes.py,sha256=fKgQRnv8r4ZCum1twz22WKMlUmDMW_qpQV9L8A5BxU8,18203
10
- tksheet/row_index.py,sha256=Yyk46EQRshGTymvaCBW-nBLmXLR2fnJJbOwIIGQpmYs,139822
11
- tksheet/sheet.py,sha256=J7WzFHzeuK8QU7EhBHmGPteGswjo0BrSo9ACNdibNBo,269459
12
- tksheet/sheet_options.py,sha256=bB-XBs1sL2w9a47wSM6GD960ZKbvQuU2VvYIK2JRSjE,14567
13
- tksheet/sorting.py,sha256=zcZPpRtP1h_xJGtGkG3E43H7deKQFnh9cMwZ1B2-aGc,17502
14
- tksheet/text_editor.py,sha256=Ksz4kT7TrCIzDhRZK9EM54M7R_5CvrwC1aeTrUPNOTg,8391
15
- tksheet/themes.py,sha256=kUUCUmvgu8vUlzfVNk9a3BEbeBcU3asNwPB_u-OejCY,18471
16
- tksheet/tksheet_types.py,sha256=1MjXR34EmvP1KfHlLTvKKVnf0VMz_LU_WOM2q4o5hfI,4598
17
- tksheet/top_left_rectangle.py,sha256=A4wWL8PFl57Pn2Ek71rASCE1-bW844cTl7bgt4tLWzI,8499
18
- tksheet-7.5.5.dist-info/licenses/LICENSE.txt,sha256=n1UvJHBr-AYNOf6ExICDsEggh9R7U4V4m_gH7FD-y-o,2305
19
- tksheet-7.5.5.dist-info/METADATA,sha256=wi3r4icBchk8jhbc7_5xFZWS70B874jVkt6ttjqmFgE,9474
20
- tksheet-7.5.5.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
21
- tksheet-7.5.5.dist-info/top_level.txt,sha256=my61PXCcck_HHAc9cq3NAlyAr3A3FXxCy9gptEOaCN8,8
22
- tksheet-7.5.5.dist-info/RECORD,,