tksheet 7.2.20__tar.gz → 7.2.22__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 (24) hide show
  1. {tksheet-7.2.20/tksheet.egg-info → tksheet-7.2.22}/PKG-INFO +2 -2
  2. {tksheet-7.2.20 → tksheet-7.2.22}/README.md +1 -1
  3. {tksheet-7.2.20 → tksheet-7.2.22}/pyproject.toml +1 -1
  4. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/__init__.py +1 -1
  5. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/column_headers.py +71 -56
  6. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/functions.py +17 -14
  7. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/main_table.py +182 -138
  8. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/other_classes.py +19 -0
  9. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/row_index.py +64 -55
  10. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/sheet.py +115 -17
  11. {tksheet-7.2.20 → tksheet-7.2.22/tksheet.egg-info}/PKG-INFO +2 -2
  12. {tksheet-7.2.20 → tksheet-7.2.22}/LICENSE.txt +0 -0
  13. {tksheet-7.2.20 → tksheet-7.2.22}/setup.cfg +0 -0
  14. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/colors.py +0 -0
  15. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/formatters.py +0 -0
  16. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/sheet_options.py +0 -0
  17. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/text_editor.py +0 -0
  18. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/themes.py +0 -0
  19. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/top_left_rectangle.py +0 -0
  20. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/types.py +0 -0
  21. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet/vars.py +0 -0
  22. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet.egg-info/SOURCES.txt +0 -0
  23. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet.egg-info/dependency_links.txt +0 -0
  24. {tksheet-7.2.20 → tksheet-7.2.22}/tksheet.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tksheet
3
- Version: 7.2.20
3
+ Version: 7.2.22
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
@@ -46,7 +46,7 @@ License-File: LICENSE.txt
46
46
 
47
47
  # <div align="center">tksheet - python tkinter table widget</div>
48
48
 
49
- [![PyPI version shields.io](https://img.shields.io/pypi/v/tksheet.svg)](https://pypi.python.org/pypi/tksheet/) ![python](https://img.shields.io/badge/python-3.8|3.9|3.10|3.11|3.12-blue) [![License: MIT](https://img.shields.io/badge/License-MIT%20-blue.svg)](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
49
+ [![PyPI version shields.io](https://img.shields.io/pypi/v/tksheet.svg)](https://pypi.python.org/pypi/tksheet/) ![python](https://img.shields.io/badge/python-3.8|3.9|3.10|3.11|3.12|3.13-blue) [![License: MIT](https://img.shields.io/badge/License-MIT%20-blue.svg)](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
50
50
 
51
51
  [![GitHub Release Date](https://img.shields.io/github/release-date-pre/ragardner/tksheet.svg)](https://github.com/ragardner/tksheet/releases) [![Downloads](https://img.shields.io/pypi/dm/tksheet.svg)](https://pypi.org/project/tksheet/)
52
52
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  # <div align="center">tksheet - python tkinter table widget</div>
6
6
 
7
- [![PyPI version shields.io](https://img.shields.io/pypi/v/tksheet.svg)](https://pypi.python.org/pypi/tksheet/) ![python](https://img.shields.io/badge/python-3.8|3.9|3.10|3.11|3.12-blue) [![License: MIT](https://img.shields.io/badge/License-MIT%20-blue.svg)](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
7
+ [![PyPI version shields.io](https://img.shields.io/pypi/v/tksheet.svg)](https://pypi.python.org/pypi/tksheet/) ![python](https://img.shields.io/badge/python-3.8|3.9|3.10|3.11|3.12|3.13-blue) [![License: MIT](https://img.shields.io/badge/License-MIT%20-blue.svg)](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
8
8
 
9
9
  [![GitHub Release Date](https://img.shields.io/github/release-date-pre/ragardner/tksheet.svg)](https://github.com/ragardner/tksheet/releases) [![Downloads](https://img.shields.io/pypi/dm/tksheet.svg)](https://pypi.org/project/tksheet/)
10
10
 
@@ -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.2.20"
9
+ version = "7.2.22"
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.2.20"
7
+ __version__ = "7.2.22"
8
8
 
9
9
  from .colors import (
10
10
  color_map,
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  import tkinter as tk
4
4
  from collections import defaultdict
5
5
  from collections.abc import (
6
- Callable,
7
6
  Hashable,
8
7
  Sequence,
9
8
  )
@@ -31,7 +30,7 @@ from .functions import (
31
30
  get_n2a,
32
31
  is_contiguous,
33
32
  new_tk_event,
34
- pickled_event_dict,
33
+ stored_event_dict,
35
34
  rounded_box_coords,
36
35
  try_binding,
37
36
  )
@@ -874,7 +873,7 @@ class ColumnHeaders(tk.Canvas):
874
873
  "displayed": disp_new_idxs,
875
874
  }
876
875
  if self.MT.undo_enabled:
877
- self.MT.undo_stack.append(pickled_event_dict(event_data))
876
+ self.MT.undo_stack.append(stored_event_dict(event_data))
878
877
  self.MT.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
879
878
  try_binding(self.ch_extra_end_drag_drop_func, event_data, "end_move_columns")
880
879
  self.MT.sheet_modified(event_data)
@@ -1190,45 +1189,44 @@ class ColumnHeaders(tk.Canvas):
1190
1189
  fc: float,
1191
1190
  sc: float,
1192
1191
  c: int,
1193
- c_2: str,
1194
- c_3: str,
1192
+ sel_cells_bg: str,
1193
+ sel_cols_bg: str,
1195
1194
  selections: dict,
1196
1195
  datacn: int,
1197
1196
  ) -> tuple[str, bool]:
1198
1197
  redrawn = False
1199
1198
  kwargs = self.get_cell_kwargs(datacn, key="highlight")
1200
1199
  if kwargs:
1201
- if kwargs[0] is not None:
1202
- c_1 = kwargs[0] if kwargs[0].startswith("#") else color_map[kwargs[0]]
1200
+ fill = kwargs[0]
1201
+ if fill and not fill.startswith("#"):
1202
+ fill = color_map[fill]
1203
1203
  if "columns" in selections and c in selections["columns"]:
1204
- tf = (
1204
+ txtfg = (
1205
1205
  self.PAR.ops.header_selected_columns_fg
1206
1206
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
1207
1207
  else kwargs[1]
1208
1208
  )
1209
- if kwargs[0] is not None:
1209
+ if fill:
1210
1210
  fill = (
1211
- f"#{int((int(c_1[1:3], 16) + int(c_3[1:3], 16)) / 2):02X}"
1212
- + f"{int((int(c_1[3:5], 16) + int(c_3[3:5], 16)) / 2):02X}"
1213
- + f"{int((int(c_1[5:], 16) + int(c_3[5:], 16)) / 2):02X}"
1211
+ f"#{int((int(fill[1:3], 16) + int(sel_cols_bg[1:3], 16)) / 2):02X}"
1212
+ + f"{int((int(fill[3:5], 16) + int(sel_cols_bg[3:5], 16)) / 2):02X}"
1213
+ + f"{int((int(fill[5:], 16) + int(sel_cols_bg[5:], 16)) / 2):02X}"
1214
1214
  )
1215
1215
  elif "cells" in selections and c in selections["cells"]:
1216
- tf = (
1216
+ txtfg = (
1217
1217
  self.PAR.ops.header_selected_cells_fg
1218
1218
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
1219
1219
  else kwargs[1]
1220
1220
  )
1221
- if kwargs[0] is not None:
1221
+ if fill:
1222
1222
  fill = (
1223
- f"#{int((int(c_1[1:3], 16) + int(c_2[1:3], 16)) / 2):02X}"
1224
- + f"{int((int(c_1[3:5], 16) + int(c_2[3:5], 16)) / 2):02X}"
1225
- + f"{int((int(c_1[5:], 16) + int(c_2[5:], 16)) / 2):02X}"
1223
+ f"#{int((int(fill[1:3], 16) + int(sel_cells_bg[1:3], 16)) / 2):02X}"
1224
+ + f"{int((int(fill[3:5], 16) + int(sel_cells_bg[3:5], 16)) / 2):02X}"
1225
+ + f"{int((int(fill[5:], 16) + int(sel_cells_bg[5:], 16)) / 2):02X}"
1226
1226
  )
1227
1227
  else:
1228
- tf = self.PAR.ops.header_fg if kwargs[1] is None else kwargs[1]
1229
- if kwargs[0] is not None:
1230
- fill = kwargs[0]
1231
- if kwargs[0] is not None:
1228
+ txtfg = self.PAR.ops.header_fg if kwargs[1] is None else kwargs[1]
1229
+ if fill:
1232
1230
  redrawn = self.redraw_highlight(
1233
1231
  fc + 1,
1234
1232
  0,
@@ -1244,12 +1242,12 @@ class ColumnHeaders(tk.Canvas):
1244
1242
  )
1245
1243
  elif not kwargs:
1246
1244
  if "columns" in selections and c in selections["columns"]:
1247
- tf = self.PAR.ops.header_selected_columns_fg
1245
+ txtfg = self.PAR.ops.header_selected_columns_fg
1248
1246
  elif "cells" in selections and c in selections["cells"]:
1249
- tf = self.PAR.ops.header_selected_cells_fg
1247
+ txtfg = self.PAR.ops.header_selected_cells_fg
1250
1248
  else:
1251
- tf = self.PAR.ops.header_fg
1252
- return tf, redrawn
1249
+ txtfg = self.PAR.ops.header_fg
1250
+ return txtfg, redrawn
1253
1251
 
1254
1252
  def redraw_highlight(
1255
1253
  self,
@@ -1463,12 +1461,12 @@ class ColumnHeaders(tk.Canvas):
1463
1461
  )
1464
1462
  self.redraw_gridline(points=points, fill=self.PAR.ops.header_grid_fg, width=1, tag="v")
1465
1463
  top = self.canvasy(0)
1466
- c_2 = (
1464
+ sel_cols_bg = (
1467
1465
  self.PAR.ops.header_selected_cells_bg
1468
1466
  if self.PAR.ops.header_selected_cells_bg.startswith("#")
1469
1467
  else color_map[self.PAR.ops.header_selected_cells_bg]
1470
1468
  )
1471
- c_3 = (
1469
+ sel_cells_bg = (
1472
1470
  self.PAR.ops.header_selected_columns_bg
1473
1471
  if self.PAR.ops.header_selected_columns_bg.startswith("#")
1474
1472
  else color_map[self.PAR.ops.header_selected_columns_bg]
@@ -1482,7 +1480,13 @@ class ColumnHeaders(tk.Canvas):
1482
1480
  crightgridln = self.MT.col_positions[c + 1]
1483
1481
  datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
1484
1482
  fill, dd_drawn = self.redraw_highlight_get_text_fg(
1485
- cleftgridln, crightgridln, c, c_2, c_3, selections, datacn
1483
+ fc=cleftgridln,
1484
+ sc=crightgridln,
1485
+ c=c,
1486
+ sel_cells_bg=sel_cells_bg,
1487
+ sel_cols_bg=sel_cols_bg,
1488
+ selections=selections,
1489
+ datacn=datacn,
1486
1490
  )
1487
1491
 
1488
1492
  if datacn in self.cell_options and "align" in self.cell_options[datacn]:
@@ -1500,7 +1504,7 @@ class ColumnHeaders(tk.Canvas):
1500
1504
  0,
1501
1505
  crightgridln,
1502
1506
  self.current_height - 1,
1503
- fill=fill,
1507
+ fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.header_grid_fg,
1504
1508
  outline=fill,
1505
1509
  tag="dd",
1506
1510
  draw_outline=not dd_drawn,
@@ -1519,7 +1523,7 @@ class ColumnHeaders(tk.Canvas):
1519
1523
  0,
1520
1524
  crightgridln,
1521
1525
  self.current_height - 1,
1522
- fill=fill,
1526
+ fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.header_grid_fg,
1523
1527
  outline=fill,
1524
1528
  tag="dd",
1525
1529
  draw_outline=not dd_drawn,
@@ -1539,7 +1543,7 @@ class ColumnHeaders(tk.Canvas):
1539
1543
  0,
1540
1544
  crightgridln,
1541
1545
  self.current_height - 1,
1542
- fill=fill,
1546
+ fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.header_grid_fg,
1543
1547
  outline=fill,
1544
1548
  tag="dd",
1545
1549
  draw_outline=not dd_drawn,
@@ -1999,20 +2003,42 @@ class ColumnHeaders(tk.Canvas):
1999
2003
 
2000
2004
  def dropdown_text_editor_modified(
2001
2005
  self,
2002
- dd_window: object,
2003
- event: dict,
2004
- modified_func: Callable | None,
2006
+ event: tk.Misc,
2005
2007
  ) -> None:
2006
- if modified_func:
2007
- modified_func(event)
2008
- dd_window.search_and_see(event)
2008
+ c = self.dropdown.get_coords()
2009
+ event_data = event_dict(
2010
+ name="table_dropdown_modified",
2011
+ sheet=self.PAR.name,
2012
+ value=self.text_editor.get(),
2013
+ loc=c,
2014
+ row=0,
2015
+ column=c,
2016
+ boxes=self.MT.get_boxes(),
2017
+ selected=self.MT.selected,
2018
+ )
2019
+ try_binding(self.dropdown.window.modified_function, event_data)
2020
+ val = self.dropdown.window.search_and_see(event_data)
2021
+ # return to tk.Text action if control/command is held down
2022
+ # or keysym was not a character
2023
+ if (hasattr(event, "state") and event.state & (0x0004 | 0x00000010)) or (
2024
+ hasattr(event, "keysym") and len(event.keysym) > 2
2025
+ ):
2026
+ return
2027
+ self.text_editor.tktext.unbind("<KeyRelease>")
2028
+ self.text_editor.autocomplete(val)
2029
+ self.text_editor.tktext.bind(
2030
+ "<KeyRelease>",
2031
+ self.dropdown_text_editor_modified,
2032
+ )
2033
+ return "break"
2009
2034
 
2010
2035
  def open_dropdown_window(self, c: int, event: object = None) -> None:
2011
2036
  self.hide_text_editor()
2012
2037
  kwargs = self.get_cell_kwargs(self.MT.datacn(c), key="dropdown")
2013
- if kwargs["state"] == "normal":
2014
- if not self.open_text_editor(event=event, c=c, dropdown=True):
2015
- return
2038
+ if kwargs["state"] == "disabled":
2039
+ return
2040
+ if kwargs["state"] == "normal" and not self.open_text_editor(event=event, c=c, dropdown=True):
2041
+ return
2016
2042
  win_h, anchor = self.get_dropdown_height_anchor(c)
2017
2043
  win_w = self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1
2018
2044
  ypos = self.current_height - 1
@@ -2026,6 +2052,8 @@ class ColumnHeaders(tk.Canvas):
2026
2052
  "outline_color": self.PAR.ops.header_selected_columns_bg,
2027
2053
  "align": self.get_cell_align(c),
2028
2054
  "values": kwargs["values"],
2055
+ "search_function": kwargs["search_function"],
2056
+ "modified_function": kwargs["modified_function"],
2029
2057
  }
2030
2058
  if self.dropdown.window:
2031
2059
  self.dropdown.window.reset(**reset_kwargs)
@@ -2038,7 +2066,6 @@ class ColumnHeaders(tk.Canvas):
2038
2066
  **reset_kwargs,
2039
2067
  single_index="c",
2040
2068
  close_dropdown_window=self.close_dropdown_window,
2041
- search_function=kwargs["search_function"],
2042
2069
  arrowkey_RIGHT=self.MT.arrowkey_RIGHT,
2043
2070
  arrowkey_LEFT=self.MT.arrowkey_LEFT,
2044
2071
  )
@@ -2049,20 +2076,8 @@ class ColumnHeaders(tk.Canvas):
2049
2076
  )
2050
2077
  if kwargs["state"] == "normal":
2051
2078
  self.text_editor.tktext.bind(
2052
- "<<TextModified>>",
2053
- lambda _x: self.dropdown_text_editor_modified(
2054
- self.dropdown.window,
2055
- event_dict(
2056
- name="header_dropdown_modified",
2057
- sheet=self.PAR.name,
2058
- value=self.text_editor.get(),
2059
- loc=c,
2060
- column=c,
2061
- boxes=self.MT.get_boxes(),
2062
- selected=self.MT.selected,
2063
- ),
2064
- kwargs["modified_function"],
2065
- ),
2079
+ "<KeyRelease>",
2080
+ self.dropdown_text_editor_modified,
2066
2081
  )
2067
2082
  self.update_idletasks()
2068
2083
  try:
@@ -2186,7 +2201,7 @@ class ColumnHeaders(tk.Canvas):
2186
2201
  self.fix_header(datacn)
2187
2202
  if not check_input_valid or self.input_valid_for_cell(datacn, value):
2188
2203
  if self.MT.undo_enabled and undo:
2189
- self.MT.undo_stack.append(pickled_event_dict(event_data))
2204
+ self.MT.undo_stack.append(stored_event_dict(event_data))
2190
2205
  self.set_cell_data(datacn=datacn, value=value)
2191
2206
  edited = True
2192
2207
  if edited and cell_resize and self.PAR.ops.cell_auto_resize_enabled:
@@ -5,7 +5,6 @@ import io
5
5
  import pickle
6
6
  import re
7
7
  import tkinter as tk
8
- import zlib
9
8
  from bisect import (
10
9
  bisect_left,
11
10
  )
@@ -16,10 +15,10 @@ from collections.abc import (
16
15
  Iterator,
17
16
  Sequence,
18
17
  )
19
- from functools import partial
20
18
  from itertools import islice, repeat
21
19
  from typing import Literal
22
20
 
21
+ from .colors import color_map
23
22
  from .formatters import (
24
23
  to_bool,
25
24
  )
@@ -32,8 +31,6 @@ from .other_classes import (
32
31
  Span,
33
32
  )
34
33
 
35
- compress = partial(zlib.compress, level=1)
36
- pickle_obj = partial(pickle.dumps, protocol=pickle.HIGHEST_PROTOCOL)
37
34
  unpickle_obj = pickle.loads
38
35
 
39
36
 
@@ -65,14 +62,6 @@ def get_data_from_clipboard(
65
62
  return [[data]]
66
63
 
67
64
 
68
- def pickle_compress(obj: object) -> bytes:
69
- return compress(pickle_obj(obj))
70
-
71
-
72
- def decompress_load(b: bytes) -> object:
73
- return pickle.loads(zlib.decompress(b))
74
-
75
-
76
65
  def tksheet_type_error(kwarg: str, valid_types: list[str], not_type: object) -> str:
77
66
  valid_types = ", ".join(f"{type_}" for type_ in valid_types)
78
67
  return f"Argument '{kwarg}' must be one of the following types: {valid_types}, " f"not {type(not_type)}."
@@ -210,8 +199,8 @@ def change_eventname(event_dict: EventDataDict, newname: str) -> EventDataDict:
210
199
  return EventDataDict({**event_dict, **{"eventname": newname}})
211
200
 
212
201
 
213
- def pickled_event_dict(d: DotDict) -> DotDict:
214
- return DotDict(name=d["eventname"], data=pickle_compress(DotDict({k: v for k, v in d.items() if k != "widget"})))
202
+ def stored_event_dict(d: DotDict) -> DotDict:
203
+ return DotDict(name=d["eventname"], data=DotDict(kv for kv in d.items() if kv[0] != "widget"))
215
204
 
216
205
 
217
206
  def len_to_idx(n: int) -> int:
@@ -438,6 +427,20 @@ def is_contiguous(iterable: Iterator[int]) -> bool:
438
427
  return all(i == (prev := prev + 1) for i in itr)
439
428
 
440
429
 
430
+ def box_is_single_cell(
431
+ r1: int,
432
+ c1: int,
433
+ r2: int,
434
+ c2: int,
435
+ ) -> bool:
436
+ return r2 - r1 == 1 and c2 - c1 == 1
437
+
438
+
439
+ def color_tup(color: str) -> tuple[int, int, int]:
440
+ res = color if color.startswith("#") else color_map[color]
441
+ return int(res[1:3], 16), int(res[3:5], 16), int(res[5:], 16)
442
+
443
+
441
444
  def down_cell_within_box(
442
445
  r: int,
443
446
  c: int,