tksheet 7.2.21__tar.gz → 7.2.23__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.2.21/tksheet.egg-info → tksheet-7.2.23}/PKG-INFO +2 -2
  2. {tksheet-7.2.21 → tksheet-7.2.23}/README.md +1 -1
  3. {tksheet-7.2.21 → tksheet-7.2.23}/pyproject.toml +1 -1
  4. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/__init__.py +1 -1
  5. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/column_headers.py +75 -64
  6. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/functions.py +31 -4
  7. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/main_table.py +182 -120
  8. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/other_classes.py +21 -1
  9. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/row_index.py +68 -64
  10. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/sheet.py +170 -23
  11. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/sheet_options.py +1 -72
  12. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/text_editor.py +11 -0
  13. tksheet-7.2.23/tksheet/themes.py +412 -0
  14. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/vars.py +4 -1
  15. {tksheet-7.2.21 → tksheet-7.2.23/tksheet.egg-info}/PKG-INFO +2 -2
  16. tksheet-7.2.21/tksheet/themes.py +0 -342
  17. {tksheet-7.2.21 → tksheet-7.2.23}/LICENSE.txt +0 -0
  18. {tksheet-7.2.21 → tksheet-7.2.23}/setup.cfg +0 -0
  19. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/colors.py +0 -0
  20. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/formatters.py +0 -0
  21. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/top_left_rectangle.py +0 -0
  22. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet/types.py +0 -0
  23. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet.egg-info/SOURCES.txt +0 -0
  24. {tksheet-7.2.21 → tksheet-7.2.23}/tksheet.egg-info/dependency_links.txt +0 -0
  25. {tksheet-7.2.21 → tksheet-7.2.23}/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.21
3
+ Version: 7.2.23
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.21"
9
+ version = "7.2.23"
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.21"
7
+ __version__ = "7.2.23"
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
  )
@@ -805,19 +804,17 @@ class ColumnHeaders(tk.Canvas):
805
804
  )
806
805
 
807
806
  def b1_release(self, event: object) -> None:
807
+ to_hide = self.being_drawn_item
808
808
  if self.being_drawn_item is not None and (to_sel := self.MT.coords_and_type(self.being_drawn_item)):
809
809
  r_to_sel, c_to_sel = self.MT.selected.row, self.MT.selected.column
810
- self.MT.hide_selection_box(self.being_drawn_item)
810
+ self.being_drawn_item = None
811
811
  self.MT.set_currently_selected(
812
812
  r_to_sel,
813
813
  c_to_sel,
814
814
  item=self.MT.create_selection_box(*to_sel, set_current=False),
815
+ run_binding=False,
815
816
  )
816
- sel_event = self.MT.get_select_event(being_drawn_item=self.being_drawn_item)
817
- try_binding(self.drag_selection_binding_func, sel_event)
818
- self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
819
- else:
820
- self.being_drawn_item = None
817
+ self.MT.hide_selection_box(to_hide)
821
818
  self.MT.bind("<MouseWheel>", self.MT.mousewheel)
822
819
  if self.width_resizing_enabled and self.rsz_w is not None and self.currently_resizing_width:
823
820
  self.drag_width_resize()
@@ -1190,45 +1187,44 @@ class ColumnHeaders(tk.Canvas):
1190
1187
  fc: float,
1191
1188
  sc: float,
1192
1189
  c: int,
1193
- c_2: str,
1194
- c_3: str,
1190
+ sel_cells_bg: str,
1191
+ sel_cols_bg: str,
1195
1192
  selections: dict,
1196
1193
  datacn: int,
1197
1194
  ) -> tuple[str, bool]:
1198
1195
  redrawn = False
1199
1196
  kwargs = self.get_cell_kwargs(datacn, key="highlight")
1200
1197
  if kwargs:
1201
- if kwargs[0] is not None:
1202
- c_1 = kwargs[0] if kwargs[0].startswith("#") else color_map[kwargs[0]]
1198
+ fill = kwargs[0]
1199
+ if fill and not fill.startswith("#"):
1200
+ fill = color_map[fill]
1203
1201
  if "columns" in selections and c in selections["columns"]:
1204
- tf = (
1202
+ txtfg = (
1205
1203
  self.PAR.ops.header_selected_columns_fg
1206
1204
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
1207
1205
  else kwargs[1]
1208
1206
  )
1209
- if kwargs[0] is not None:
1207
+ if fill:
1210
1208
  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}"
1209
+ f"#{int((int(fill[1:3], 16) + int(sel_cols_bg[1:3], 16)) / 2):02X}"
1210
+ + f"{int((int(fill[3:5], 16) + int(sel_cols_bg[3:5], 16)) / 2):02X}"
1211
+ + f"{int((int(fill[5:], 16) + int(sel_cols_bg[5:], 16)) / 2):02X}"
1214
1212
  )
1215
1213
  elif "cells" in selections and c in selections["cells"]:
1216
- tf = (
1214
+ txtfg = (
1217
1215
  self.PAR.ops.header_selected_cells_fg
1218
1216
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
1219
1217
  else kwargs[1]
1220
1218
  )
1221
- if kwargs[0] is not None:
1219
+ if fill:
1222
1220
  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}"
1221
+ f"#{int((int(fill[1:3], 16) + int(sel_cells_bg[1:3], 16)) / 2):02X}"
1222
+ + f"{int((int(fill[3:5], 16) + int(sel_cells_bg[3:5], 16)) / 2):02X}"
1223
+ + f"{int((int(fill[5:], 16) + int(sel_cells_bg[5:], 16)) / 2):02X}"
1226
1224
  )
1227
1225
  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:
1226
+ txtfg = self.PAR.ops.header_fg if kwargs[1] is None else kwargs[1]
1227
+ if fill:
1232
1228
  redrawn = self.redraw_highlight(
1233
1229
  fc + 1,
1234
1230
  0,
@@ -1244,12 +1240,12 @@ class ColumnHeaders(tk.Canvas):
1244
1240
  )
1245
1241
  elif not kwargs:
1246
1242
  if "columns" in selections and c in selections["columns"]:
1247
- tf = self.PAR.ops.header_selected_columns_fg
1243
+ txtfg = self.PAR.ops.header_selected_columns_fg
1248
1244
  elif "cells" in selections and c in selections["cells"]:
1249
- tf = self.PAR.ops.header_selected_cells_fg
1245
+ txtfg = self.PAR.ops.header_selected_cells_fg
1250
1246
  else:
1251
- tf = self.PAR.ops.header_fg
1252
- return tf, redrawn
1247
+ txtfg = self.PAR.ops.header_fg
1248
+ return txtfg, redrawn
1253
1249
 
1254
1250
  def redraw_highlight(
1255
1251
  self,
@@ -1463,12 +1459,12 @@ class ColumnHeaders(tk.Canvas):
1463
1459
  )
1464
1460
  self.redraw_gridline(points=points, fill=self.PAR.ops.header_grid_fg, width=1, tag="v")
1465
1461
  top = self.canvasy(0)
1466
- c_2 = (
1462
+ sel_cols_bg = (
1467
1463
  self.PAR.ops.header_selected_cells_bg
1468
1464
  if self.PAR.ops.header_selected_cells_bg.startswith("#")
1469
1465
  else color_map[self.PAR.ops.header_selected_cells_bg]
1470
1466
  )
1471
- c_3 = (
1467
+ sel_cells_bg = (
1472
1468
  self.PAR.ops.header_selected_columns_bg
1473
1469
  if self.PAR.ops.header_selected_columns_bg.startswith("#")
1474
1470
  else color_map[self.PAR.ops.header_selected_columns_bg]
@@ -1482,7 +1478,13 @@ class ColumnHeaders(tk.Canvas):
1482
1478
  crightgridln = self.MT.col_positions[c + 1]
1483
1479
  datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
1484
1480
  fill, dd_drawn = self.redraw_highlight_get_text_fg(
1485
- cleftgridln, crightgridln, c, c_2, c_3, selections, datacn
1481
+ fc=cleftgridln,
1482
+ sc=crightgridln,
1483
+ c=c,
1484
+ sel_cells_bg=sel_cells_bg,
1485
+ sel_cols_bg=sel_cols_bg,
1486
+ selections=selections,
1487
+ datacn=datacn,
1486
1488
  )
1487
1489
 
1488
1490
  if datacn in self.cell_options and "align" in self.cell_options[datacn]:
@@ -1500,7 +1502,7 @@ class ColumnHeaders(tk.Canvas):
1500
1502
  0,
1501
1503
  crightgridln,
1502
1504
  self.current_height - 1,
1503
- fill=fill,
1505
+ fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.header_grid_fg,
1504
1506
  outline=fill,
1505
1507
  tag="dd",
1506
1508
  draw_outline=not dd_drawn,
@@ -1519,7 +1521,7 @@ class ColumnHeaders(tk.Canvas):
1519
1521
  0,
1520
1522
  crightgridln,
1521
1523
  self.current_height - 1,
1522
- fill=fill,
1524
+ fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.header_grid_fg,
1523
1525
  outline=fill,
1524
1526
  tag="dd",
1525
1527
  draw_outline=not dd_drawn,
@@ -1539,7 +1541,7 @@ class ColumnHeaders(tk.Canvas):
1539
1541
  0,
1540
1542
  crightgridln,
1541
1543
  self.current_height - 1,
1542
- fill=fill,
1544
+ fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.header_grid_fg,
1543
1545
  outline=fill,
1544
1546
  tag="dd",
1545
1547
  draw_outline=not dd_drawn,
@@ -1768,7 +1770,6 @@ class ColumnHeaders(tk.Canvas):
1768
1770
  h = self.current_height + 1
1769
1771
  if text is None:
1770
1772
  text = self.get_cell_data(self.MT.datacn(c), none_to_empty_str=True, redirect_int=True)
1771
- bg, fg = self.PAR.ops.header_bg, self.PAR.ops.header_fg
1772
1773
  kwargs = {
1773
1774
  "menu_kwargs": DotDict(
1774
1775
  {
@@ -1786,8 +1787,10 @@ class ColumnHeaders(tk.Canvas):
1786
1787
  "width": w,
1787
1788
  "height": h,
1788
1789
  "show_border": True,
1789
- "bg": bg,
1790
- "fg": fg,
1790
+ "bg": self.PAR.ops.header_editor_bg,
1791
+ "fg": self.PAR.ops.header_editor_fg,
1792
+ "select_bg": self.PAR.ops.header_editor_select_bg,
1793
+ "select_fg": self.PAR.ops.header_editor_select_fg,
1791
1794
  "align": self.get_cell_align(c),
1792
1795
  "c": c,
1793
1796
  }
@@ -1999,26 +2002,46 @@ class ColumnHeaders(tk.Canvas):
1999
2002
 
2000
2003
  def dropdown_text_editor_modified(
2001
2004
  self,
2002
- dd_window: object,
2003
- event: dict,
2004
- modified_func: Callable | None,
2005
+ event: tk.Misc,
2005
2006
  ) -> None:
2006
- if modified_func:
2007
- modified_func(event)
2008
- dd_window.search_and_see(event)
2007
+ c = self.dropdown.get_coords()
2008
+ event_data = event_dict(
2009
+ name="table_dropdown_modified",
2010
+ sheet=self.PAR.name,
2011
+ value=self.text_editor.get(),
2012
+ loc=c,
2013
+ row=0,
2014
+ column=c,
2015
+ boxes=self.MT.get_boxes(),
2016
+ selected=self.MT.selected,
2017
+ )
2018
+ try_binding(self.dropdown.window.modified_function, event_data)
2019
+ # return to tk.Text action if control/command is held down
2020
+ # or keysym was not a character
2021
+ if (hasattr(event, "state") and event.state & (0x0004 | 0x00000010)) or (
2022
+ hasattr(event, "keysym") and len(event.keysym) > 2 and event.keysym != "space"
2023
+ ):
2024
+ return
2025
+ self.text_editor.autocomplete(self.dropdown.window.search_and_see(event_data))
2026
+ return "break"
2009
2027
 
2010
2028
  def open_dropdown_window(self, c: int, event: object = None) -> None:
2011
2029
  self.hide_text_editor()
2012
2030
  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
2031
+ if kwargs["state"] == "disabled":
2032
+ return
2033
+ if kwargs["state"] == "normal" and not self.open_text_editor(event=event, c=c, dropdown=True):
2034
+ return
2016
2035
  win_h, anchor = self.get_dropdown_height_anchor(c)
2017
2036
  win_w = self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1
2018
2037
  ypos = self.current_height - 1
2019
2038
  reset_kwargs = {
2020
2039
  "r": 0,
2021
2040
  "c": c,
2041
+ "bg": self.PAR.ops.header_editor_bg,
2042
+ "fg": self.PAR.ops.header_editor_fg,
2043
+ "select_bg": self.PAR.ops.header_editor_select_bg,
2044
+ "select_fg": self.PAR.ops.header_editor_select_fg,
2022
2045
  "width": win_w,
2023
2046
  "height": win_h,
2024
2047
  "font": self.PAR.ops.header_font,
@@ -2026,6 +2049,8 @@ class ColumnHeaders(tk.Canvas):
2026
2049
  "outline_color": self.PAR.ops.header_selected_columns_bg,
2027
2050
  "align": self.get_cell_align(c),
2028
2051
  "values": kwargs["values"],
2052
+ "search_function": kwargs["search_function"],
2053
+ "modified_function": kwargs["modified_function"],
2029
2054
  }
2030
2055
  if self.dropdown.window:
2031
2056
  self.dropdown.window.reset(**reset_kwargs)
@@ -2038,7 +2063,6 @@ class ColumnHeaders(tk.Canvas):
2038
2063
  **reset_kwargs,
2039
2064
  single_index="c",
2040
2065
  close_dropdown_window=self.close_dropdown_window,
2041
- search_function=kwargs["search_function"],
2042
2066
  arrowkey_RIGHT=self.MT.arrowkey_RIGHT,
2043
2067
  arrowkey_LEFT=self.MT.arrowkey_LEFT,
2044
2068
  )
@@ -2047,24 +2071,12 @@ class ColumnHeaders(tk.Canvas):
2047
2071
  window=self.dropdown.window,
2048
2072
  anchor=anchor,
2049
2073
  )
2074
+ self.update_idletasks()
2050
2075
  if kwargs["state"] == "normal":
2051
2076
  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
- ),
2077
+ "<KeyRelease>",
2078
+ self.dropdown_text_editor_modified,
2066
2079
  )
2067
- self.update_idletasks()
2068
2080
  try:
2069
2081
  self.after(1, lambda: self.text_editor.tktext.focus())
2070
2082
  self.after(2, self.text_editor.window.scroll_to_bottom())
@@ -2072,7 +2084,6 @@ class ColumnHeaders(tk.Canvas):
2072
2084
  return
2073
2085
  redraw = False
2074
2086
  else:
2075
- self.update_idletasks()
2076
2087
  self.dropdown.window.bind("<FocusOut>", lambda _x: self.close_dropdown_window(c))
2077
2088
  self.dropdown.window.bind("<Escape>", self.close_dropdown_window)
2078
2089
  self.dropdown.window.focus_set()
@@ -18,6 +18,7 @@ from collections.abc import (
18
18
  from itertools import islice, repeat
19
19
  from typing import Literal
20
20
 
21
+ from .colors import color_map
21
22
  from .formatters import (
22
23
  to_bool,
23
24
  )
@@ -426,6 +427,20 @@ def is_contiguous(iterable: Iterator[int]) -> bool:
426
427
  return all(i == (prev := prev + 1) for i in itr)
427
428
 
428
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
+
429
444
  def down_cell_within_box(
430
445
  r: int,
431
446
  c: int,
@@ -1400,12 +1415,24 @@ def mod_span_widget(span: Span, widget: object) -> Span:
1400
1415
  def mod_event_val(
1401
1416
  event_data: EventDataDict,
1402
1417
  val: object,
1403
- loc: Loc | int,
1418
+ loc: Loc | None = None,
1419
+ row: int | None = None,
1420
+ column: int | None = None,
1404
1421
  ) -> EventDataDict:
1405
1422
  event_data.value = val
1406
- event_data.loc = Loc(*loc)
1407
- event_data.row = loc[0]
1408
- event_data.column = loc[1]
1423
+ if isinstance(loc, tuple):
1424
+ event_data.loc = Loc(*loc)
1425
+ event_data.row = loc[0]
1426
+ event_data.column = loc[1]
1427
+
1428
+ elif isinstance(row, int):
1429
+ event_data.loc = Loc(row=row)
1430
+ event_data.row = row
1431
+
1432
+ elif isinstance(column, int):
1433
+ event_data.loc = Loc(column=column)
1434
+ event_data.column = column
1435
+
1409
1436
  return event_data
1410
1437
 
1411
1438