tksheet 7.2.21__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.21/tksheet.egg-info → tksheet-7.2.22}/PKG-INFO +2 -2
  2. {tksheet-7.2.21 → tksheet-7.2.22}/README.md +1 -1
  3. {tksheet-7.2.21 → tksheet-7.2.22}/pyproject.toml +1 -1
  4. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/__init__.py +1 -1
  5. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/column_headers.py +68 -53
  6. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/functions.py +15 -0
  7. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/main_table.py +141 -98
  8. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/other_classes.py +19 -0
  9. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/row_index.py +61 -52
  10. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/sheet.py +104 -6
  11. {tksheet-7.2.21 → tksheet-7.2.22/tksheet.egg-info}/PKG-INFO +2 -2
  12. {tksheet-7.2.21 → tksheet-7.2.22}/LICENSE.txt +0 -0
  13. {tksheet-7.2.21 → tksheet-7.2.22}/setup.cfg +0 -0
  14. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/colors.py +0 -0
  15. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/formatters.py +0 -0
  16. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/sheet_options.py +0 -0
  17. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/text_editor.py +0 -0
  18. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/themes.py +0 -0
  19. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/top_left_rectangle.py +0 -0
  20. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/types.py +0 -0
  21. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet/vars.py +0 -0
  22. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet.egg-info/SOURCES.txt +0 -0
  23. {tksheet-7.2.21 → tksheet-7.2.22}/tksheet.egg-info/dependency_links.txt +0 -0
  24. {tksheet-7.2.21 → 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.21
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.21"
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.21"
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
  )
@@ -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:
@@ -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,
@@ -51,7 +51,9 @@ from .formatters import (
51
51
  from .functions import (
52
52
  add_to_displayed,
53
53
  b_index,
54
+ box_is_single_cell,
54
55
  cell_right_within_box,
56
+ color_tup,
55
57
  consecutive_ranges,
56
58
  diff_gen,
57
59
  diff_list,
@@ -72,9 +74,9 @@ from .functions import (
72
74
  mod_span_widget,
73
75
  move_elements_by_mapping,
74
76
  new_tk_event,
75
- stored_event_dict,
76
77
  rounded_box_coords,
77
78
  span_idxs_post_move,
79
+ stored_event_dict,
78
80
  try_binding,
79
81
  unpickle_obj,
80
82
  )
@@ -2760,7 +2762,7 @@ class MainTable(tk.Canvas):
2760
2762
  self.rc_insert_row_enabled = True
2761
2763
  self.rc_popup_menus_enabled = True
2762
2764
  self.rc_select_enabled = True
2763
- if binding in ("all", "right_click_popup_menu", "rc_popup_menu"):
2765
+ if binding in ("all", "right_click_popup_menu", "rc_popup_menu", "rc_menu"):
2764
2766
  self.rc_popup_menus_enabled = True
2765
2767
  self.rc_select_enabled = True
2766
2768
  if binding in ("all", "right_click_select", "rc_select"):
@@ -2823,7 +2825,7 @@ class MainTable(tk.Canvas):
2823
2825
  self.rc_insert_column_enabled = False
2824
2826
  if binding in bind_add_rows:
2825
2827
  self.rc_insert_row_enabled = False
2826
- if binding in ("all", "right_click_popup_menu", "rc_popup_menu"):
2828
+ if binding in ("all", "right_click_popup_menu", "rc_popup_menu", "rc_menu"):
2827
2829
  self.rc_popup_menus_enabled = False
2828
2830
  if binding in ("all", "right_click_select", "rc_select"):
2829
2831
  self.rc_select_enabled = False
@@ -5157,69 +5159,82 @@ class MainTable(tk.Canvas):
5157
5159
  fr: int | float,
5158
5160
  sc: int | float,
5159
5161
  sr: int | float,
5160
- c_2_: tuple[int, int, int],
5161
- c_3_: tuple[int, int, int],
5162
- c_4_: tuple[int, int, int],
5162
+ sel_cells_bg: tuple[int, int, int],
5163
+ sel_cols_bg: tuple[int, int, int],
5164
+ sel_rows_bg: tuple[int, int, int],
5163
5165
  selections: dict,
5164
5166
  datarn: int,
5165
5167
  datacn: int,
5166
5168
  can_width: int | None,
5169
+ dont_blend: bool,
5170
+ alternate_color: Highlight | None,
5167
5171
  ) -> str:
5168
5172
  redrawn = False
5169
5173
  if (datarn, datacn) in self.progress_bars:
5170
5174
  kwargs = self.progress_bars[(datarn, datacn)]
5171
5175
  else:
5172
5176
  kwargs = self.get_cell_kwargs(datarn, datacn, key="highlight")
5173
- if not kwargs and (self.PAR.ops.alternate_color and r % 2):
5174
- kwargs = Highlight(
5175
- bg=self.PAR.ops.alternate_color,
5176
- fg=None,
5177
- end=False,
5178
- )
5177
+ if alt := bool(not kwargs and alternate_color and r % 2):
5178
+ kwargs = alternate_color
5179
+
5179
5180
  if kwargs:
5180
- if kwargs[0] is not None:
5181
- c_1 = kwargs[0] if kwargs[0].startswith("#") else color_map[kwargs[0]]
5182
- if "cells" in selections and (r, c) in selections["cells"]:
5183
- tf = (
5181
+ fill = kwargs[0]
5182
+ if fill and not fill.startswith("#"):
5183
+ fill = color_map[fill]
5184
+
5185
+ # cell is a single currently selected cell box
5186
+ # not highlighted
5187
+ # on an alternate row color
5188
+ if alt and dont_blend:
5189
+ txtfg = self.PAR.ops.table_fg
5190
+
5191
+ # cell is highlighted and cell selected
5192
+ elif "cells" in selections and (r, c) in selections["cells"]:
5193
+ txtfg = (
5184
5194
  self.PAR.ops.table_selected_cells_fg
5185
5195
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
5186
5196
  else kwargs[1]
5187
5197
  )
5188
- if kwargs[0] is not None:
5198
+ if fill:
5189
5199
  fill = (
5190
- f"#{int((int(c_1[1:3], 16) + c_2_[0]) / 2):02X}"
5191
- + f"{int((int(c_1[3:5], 16) + c_2_[1]) / 2):02X}"
5192
- + f"{int((int(c_1[5:], 16) + c_2_[2]) / 2):02X}"
5200
+ f"#{int((int(fill[1:3], 16) + sel_cells_bg[0]) / 2):02X}"
5201
+ + f"{int((int(fill[3:5], 16) + sel_cells_bg[1]) / 2):02X}"
5202
+ + f"{int((int(fill[5:], 16) + sel_cells_bg[2]) / 2):02X}"
5193
5203
  )
5204
+
5205
+ # cell is highlighted and row selected
5194
5206
  elif "rows" in selections and r in selections["rows"]:
5195
- tf = (
5207
+ txtfg = (
5196
5208
  self.PAR.ops.table_selected_rows_fg
5197
5209
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
5198
5210
  else kwargs[1]
5199
5211
  )
5200
- if kwargs[0] is not None:
5212
+ if fill:
5201
5213
  fill = (
5202
- f"#{int((int(c_1[1:3], 16) + c_4_[0]) / 2):02X}"
5203
- + f"{int((int(c_1[3:5], 16) + c_4_[1]) / 2):02X}"
5204
- + f"{int((int(c_1[5:], 16) + c_4_[2]) / 2):02X}"
5214
+ f"#{int((int(fill[1:3], 16) + sel_rows_bg[0]) / 2):02X}"
5215
+ + f"{int((int(fill[3:5], 16) + sel_rows_bg[1]) / 2):02X}"
5216
+ + f"{int((int(fill[5:], 16) + sel_rows_bg[2]) / 2):02X}"
5205
5217
  )
5218
+
5219
+ # cell is highlighted and column selected
5206
5220
  elif "columns" in selections and c in selections["columns"]:
5207
- tf = (
5221
+ txtfg = (
5208
5222
  self.PAR.ops.table_selected_columns_fg
5209
5223
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
5210
5224
  else kwargs[1]
5211
5225
  )
5212
- if kwargs[0] is not None:
5226
+ if fill:
5213
5227
  fill = (
5214
- f"#{int((int(c_1[1:3], 16) + c_3_[0]) / 2):02X}"
5215
- + f"{int((int(c_1[3:5], 16) + c_3_[1]) / 2):02X}"
5216
- + f"{int((int(c_1[5:], 16) + c_3_[2]) / 2):02X}"
5228
+ f"#{int((int(fill[1:3], 16) + sel_cols_bg[0]) / 2):02X}"
5229
+ + f"{int((int(fill[3:5], 16) + sel_cols_bg[1]) / 2):02X}"
5230
+ + f"{int((int(fill[5:], 16) + sel_cols_bg[2]) / 2):02X}"
5217
5231
  )
5232
+
5233
+ # cell is just highlighted
5218
5234
  else:
5219
- tf = self.PAR.ops.table_fg if kwargs[1] is None else kwargs[1]
5220
- if kwargs[0] is not None:
5221
- fill = kwargs[0]
5222
- if kwargs[0] is not None:
5235
+ txtfg = self.PAR.ops.table_fg if kwargs[1] is None else kwargs[1]
5236
+
5237
+ if fill:
5223
5238
  highlight_fn = partial(
5224
5239
  self.redraw_highlight,
5225
5240
  x1=fc + 1,
@@ -5249,14 +5264,14 @@ class MainTable(tk.Canvas):
5249
5264
  )
5250
5265
  elif not kwargs:
5251
5266
  if "cells" in selections and (r, c) in selections["cells"]:
5252
- tf = self.PAR.ops.table_selected_cells_fg
5267
+ txtfg = self.PAR.ops.table_selected_cells_fg
5253
5268
  elif "rows" in selections and r in selections["rows"]:
5254
- tf = self.PAR.ops.table_selected_rows_fg
5269
+ txtfg = self.PAR.ops.table_selected_rows_fg
5255
5270
  elif "columns" in selections and c in selections["columns"]:
5256
- tf = self.PAR.ops.table_selected_columns_fg
5271
+ txtfg = self.PAR.ops.table_selected_columns_fg
5257
5272
  else:
5258
- tf = self.PAR.ops.table_fg
5259
- return tf, redrawn
5273
+ txtfg = self.PAR.ops.table_fg
5274
+ return txtfg, redrawn
5260
5275
 
5261
5276
  def redraw_highlight(self, x1, y1, x2, y2, fill, outline, tag, can_width=None, pc=None):
5262
5277
  if not is_type_int(pc) or pc >= 100:
@@ -5638,24 +5653,36 @@ class MainTable(tk.Canvas):
5638
5653
  )
5639
5654
  if redraw_table:
5640
5655
  selections = self.get_redraw_selections(text_start_row, grid_end_row, text_start_col, grid_end_col)
5641
- c_2 = (
5642
- self.PAR.ops.table_selected_cells_bg
5643
- if self.PAR.ops.table_selected_cells_bg.startswith("#")
5644
- else color_map[self.PAR.ops.table_selected_cells_bg]
5645
- )
5646
- c_2_ = (int(c_2[1:3], 16), int(c_2[3:5], 16), int(c_2[5:], 16))
5647
- c_3 = (
5648
- self.PAR.ops.table_selected_columns_bg
5649
- if self.PAR.ops.table_selected_columns_bg.startswith("#")
5650
- else color_map[self.PAR.ops.table_selected_columns_bg]
5651
- )
5652
- c_3_ = (int(c_3[1:3], 16), int(c_3[3:5], 16), int(c_3[5:], 16))
5653
- c_4 = (
5654
- self.PAR.ops.table_selected_rows_bg
5655
- if self.PAR.ops.table_selected_rows_bg.startswith("#")
5656
- else color_map[self.PAR.ops.table_selected_rows_bg]
5657
- )
5658
- c_4_ = (int(c_4[1:3], 16), int(c_4[3:5], 16), int(c_4[5:], 16))
5656
+ sel_cells_bg = color_tup(self.PAR.ops.table_selected_cells_bg)
5657
+ sel_cols_bg = color_tup(self.PAR.ops.table_selected_columns_bg)
5658
+ sel_rows_bg = color_tup(self.PAR.ops.table_selected_rows_bg)
5659
+ if self.selected:
5660
+ current_loc = (self.selected.row, self.selected.column)
5661
+ else:
5662
+ current_loc = tuple()
5663
+ if self.PAR.ops.alternate_color:
5664
+ alternate_color = Highlight(
5665
+ bg=self.PAR.ops.alternate_color,
5666
+ fg=None,
5667
+ end=False,
5668
+ )
5669
+ if self.selected and box_is_single_cell(*self.selected.box) and self.PAR.ops.show_selected_cells_border:
5670
+ dont_blend = current_loc
5671
+ else:
5672
+ dont_blend = tuple()
5673
+ else:
5674
+ alternate_color = None
5675
+ dont_blend = tuple()
5676
+
5677
+ if not self.PAR.ops.show_selected_cells_border:
5678
+ override = (
5679
+ color_tup(self.PAR.ops.table_selected_cells_fg),
5680
+ color_tup(self.PAR.ops.table_selected_columns_fg),
5681
+ color_tup(self.PAR.ops.table_selected_rows_fg),
5682
+ )
5683
+ else:
5684
+ override = tuple()
5685
+
5659
5686
  rows_ = tuple(range(text_start_row, text_end_row))
5660
5687
  font = self.PAR.ops.table_font
5661
5688
  dd_coords = self.dropdown.get_coords()
@@ -5672,19 +5699,21 @@ class MainTable(tk.Canvas):
5672
5699
  datacn = self.datacn(c)
5673
5700
 
5674
5701
  fill, dd_drawn = self.redraw_highlight_get_text_fg(
5675
- r,
5676
- c,
5677
- cleftgridln,
5678
- rtopgridln,
5679
- crightgridln,
5680
- rbotgridln,
5681
- c_2_,
5682
- c_3_,
5683
- c_4_,
5684
- selections,
5685
- datarn,
5686
- datacn,
5687
- can_width,
5702
+ r=r,
5703
+ c=c,
5704
+ fc=cleftgridln,
5705
+ fr=rtopgridln,
5706
+ sc=crightgridln,
5707
+ sr=rbotgridln,
5708
+ sel_cells_bg=override[0] if override and (r, c) == current_loc else sel_cells_bg,
5709
+ sel_cols_bg=override[1] if override and (r, c) == current_loc else sel_cols_bg,
5710
+ sel_rows_bg=override[2] if override and (r, c) == current_loc else sel_rows_bg,
5711
+ selections=selections,
5712
+ datarn=datarn,
5713
+ datacn=datacn,
5714
+ can_width=can_width,
5715
+ dont_blend=(r, c) == dont_blend,
5716
+ alternate_color=alternate_color,
5688
5717
  )
5689
5718
  align = self.get_cell_kwargs(datarn, datacn, key="align")
5690
5719
  if align:
@@ -5701,7 +5730,7 @@ class MainTable(tk.Canvas):
5701
5730
  rtopgridln,
5702
5731
  crightgridln,
5703
5732
  self.row_positions[r + 1],
5704
- fill=fill,
5733
+ fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.table_grid_fg,
5705
5734
  outline=fill,
5706
5735
  tag=f"dd_{r}_{c}",
5707
5736
  draw_outline=not dd_drawn,
@@ -5719,7 +5748,7 @@ class MainTable(tk.Canvas):
5719
5748
  rtopgridln,
5720
5749
  crightgridln,
5721
5750
  self.row_positions[r + 1],
5722
- fill=fill,
5751
+ fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.table_grid_fg,
5723
5752
  outline=fill,
5724
5753
  tag=f"dd_{r}_{c}",
5725
5754
  draw_outline=not dd_drawn,
@@ -5738,7 +5767,7 @@ class MainTable(tk.Canvas):
5738
5767
  rtopgridln,
5739
5768
  crightgridln,
5740
5769
  self.row_positions[r + 1],
5741
- fill=fill,
5770
+ fill=fill if kwargs["state"] != "disabled" else self.PAR.ops.table_grid_fg,
5742
5771
  outline=fill,
5743
5772
  tag=f"dd_{r}_{c}",
5744
5773
  draw_outline=not dd_drawn,
@@ -6904,6 +6933,8 @@ class MainTable(tk.Canvas):
6904
6933
  new_r, new_c = down_cell_within_box(r, c, r1, c1, r2, c2, numrows, numcols)
6905
6934
  else:
6906
6935
  new_r, new_c = None, None
6936
+ else:
6937
+ new_r, new_c = None, None
6907
6938
  if isinstance(new_r, int):
6908
6939
  self.set_currently_selected(new_r, new_c, item=self.selected.fill_iid)
6909
6940
  self.see(
@@ -6958,6 +6989,8 @@ class MainTable(tk.Canvas):
6958
6989
  bottom_right_corner=True,
6959
6990
  check_cell_visibility=True,
6960
6991
  )
6992
+ if not self.PAR.ops.show_selected_cells_border:
6993
+ self.refresh()
6961
6994
  return "break"
6962
6995
 
6963
6996
  def get_space_bot(self, r: int, text_editor_h: int | None = None) -> int:
@@ -7015,13 +7048,34 @@ class MainTable(tk.Canvas):
7015
7048
 
7016
7049
  def dropdown_text_editor_modified(
7017
7050
  self,
7018
- dd_window: object,
7019
- event: dict,
7020
- modified_func: Callable | None,
7051
+ event: tk.Misc,
7021
7052
  ) -> None:
7022
- if modified_func:
7023
- modified_func(event)
7024
- dd_window.search_and_see(event)
7053
+ r, c = self.dropdown.get_coords()
7054
+ event_data = event_dict(
7055
+ name="table_dropdown_modified",
7056
+ sheet=self.PAR.name,
7057
+ value=self.text_editor.get(),
7058
+ loc=Loc(r, c),
7059
+ row=r,
7060
+ column=c,
7061
+ boxes=self.get_boxes(),
7062
+ selected=self.selected,
7063
+ )
7064
+ try_binding(self.dropdown.window.modified_function, event_data)
7065
+ val = self.dropdown.window.search_and_see(event_data)
7066
+ # return to tk.Text action if control/command is held down
7067
+ # or keysym was not a character
7068
+ if (hasattr(event, "state") and event.state & (0x0004 | 0x00000010)) or (
7069
+ hasattr(event, "keysym") and len(event.keysym) > 2
7070
+ ):
7071
+ return
7072
+ self.text_editor.tktext.unbind("<KeyRelease>")
7073
+ self.text_editor.autocomplete(val)
7074
+ self.text_editor.tktext.bind(
7075
+ "<KeyRelease>",
7076
+ self.dropdown_text_editor_modified,
7077
+ )
7078
+ return "break"
7025
7079
 
7026
7080
  # c is displayed col
7027
7081
  def open_dropdown_window(
@@ -7034,9 +7088,10 @@ class MainTable(tk.Canvas):
7034
7088
  datarn = self.datarn(r)
7035
7089
  datacn = self.datacn(c)
7036
7090
  kwargs = self.get_cell_kwargs(datarn, datacn, key="dropdown")
7037
- if kwargs["state"] == "normal":
7038
- if not self.open_text_editor(event=event, r=r, c=c, dropdown=True):
7039
- return
7091
+ if kwargs["state"] == "disabled":
7092
+ return
7093
+ if kwargs["state"] == "normal" and not self.open_text_editor(event=event, r=r, c=c, dropdown=True):
7094
+ return
7040
7095
  win_h, anchor = self.get_dropdown_height_anchor(r, c)
7041
7096
  win_w = self.col_positions[c + 1] - self.col_positions[c] + 1
7042
7097
  if anchor == "nw":
@@ -7057,6 +7112,8 @@ class MainTable(tk.Canvas):
7057
7112
  "outline_color": self.get_selected_box_bg_fg(type_="cells")[1],
7058
7113
  "align": self.get_cell_align(r, c),
7059
7114
  "values": kwargs["values"],
7115
+ "search_function": kwargs["search_function"],
7116
+ "modified_function": kwargs["modified_function"],
7060
7117
  }
7061
7118
  if self.dropdown.window:
7062
7119
  self.dropdown.window.reset(**reset_kwargs)
@@ -7068,7 +7125,6 @@ class MainTable(tk.Canvas):
7068
7125
  self.winfo_toplevel(),
7069
7126
  **reset_kwargs,
7070
7127
  close_dropdown_window=self.close_dropdown_window,
7071
- search_function=kwargs["search_function"],
7072
7128
  arrowkey_RIGHT=self.arrowkey_RIGHT,
7073
7129
  arrowkey_LEFT=self.arrowkey_LEFT,
7074
7130
  )
@@ -7079,22 +7135,9 @@ class MainTable(tk.Canvas):
7079
7135
  )
7080
7136
  if kwargs["state"] == "normal":
7081
7137
  self.text_editor.tktext.bind(
7082
- "<<TextModified>>",
7083
- lambda _: self.dropdown.window.search_and_see(
7084
- event_dict(
7085
- name="table_dropdown_modified",
7086
- sheet=self.PAR.name,
7087
- value=self.text_editor.get(),
7088
- loc=Loc(r, c),
7089
- row=r,
7090
- column=c,
7091
- boxes=self.get_boxes(),
7092
- selected=self.selected,
7093
- )
7094
- ),
7138
+ "<KeyRelease>",
7139
+ self.dropdown_text_editor_modified,
7095
7140
  )
7096
- if kwargs["modified_function"] is not None:
7097
- self.dropdown.window.modified_function = kwargs["modified_function"]
7098
7141
  self.update_idletasks()
7099
7142
  try:
7100
7143
  self.after(1, lambda: self.text_editor.tktext.focus())
@@ -489,6 +489,25 @@ class TextEditorStorage:
489
489
  if self.window:
490
490
  return self.window.get()
491
491
  return ""
492
+
493
+ def set(self, value: str) -> None:
494
+ if not self.window:
495
+ return
496
+ self.window.set_text(value)
497
+
498
+ def highlight_from(self, r: int | str, c: int | str) -> None:
499
+ index = self.window.tktext.index(f"{r}.{c}")
500
+ self.window.tktext.tag_add('sel', index, 'end')
501
+ self.window.tktext.mark_set('insert', f"{r}.{c}")
502
+
503
+ def autocomplete(self, value: str | None) -> None:
504
+ current_val = self.get()
505
+ if not value or len(current_val) >= len(value) or current_val != value[:len(current_val)]:
506
+ return
507
+ cursor_pos = self.tktext.index('insert')
508
+ line, column = cursor_pos.split('.')
509
+ self.window.set_text(value)
510
+ self.highlight_from(line, column)
492
511
 
493
512
  @property
494
513
  def tktext(self) -> object:
@@ -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
  Generator,
8
7
  Hashable,
9
8
  Iterator,
@@ -1222,27 +1221,28 @@ class RowIndex(tk.Canvas):
1222
1221
  fr: float,
1223
1222
  sr: float,
1224
1223
  r: int,
1225
- c_2: str,
1226
- c_3: str,
1224
+ sel_cells_bg: str,
1225
+ sel_rows_bg: str,
1227
1226
  selections: dict,
1228
1227
  datarn: int,
1229
1228
  ) -> tuple[str, str, bool]:
1230
1229
  redrawn = False
1231
1230
  kwargs = self.get_cell_kwargs(datarn, key="highlight")
1232
1231
  if kwargs:
1233
- if kwargs[0] is not None:
1234
- c_1 = kwargs[0] if kwargs[0].startswith("#") else color_map[kwargs[0]]
1232
+ fill = kwargs[0]
1233
+ if fill and not fill.startswith("#"):
1234
+ fill = color_map[fill]
1235
1235
  if "rows" in selections and r in selections["rows"]:
1236
1236
  txtfg = (
1237
1237
  self.PAR.ops.index_selected_rows_fg
1238
1238
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
1239
1239
  else kwargs[1]
1240
1240
  )
1241
- if kwargs[0] is not None:
1241
+ if fill:
1242
1242
  fill = (
1243
- f"#{int((int(c_1[1:3], 16) + int(c_3[1:3], 16)) / 2):02X}"
1244
- + f"{int((int(c_1[3:5], 16) + int(c_3[3:5], 16)) / 2):02X}"
1245
- + f"{int((int(c_1[5:], 16) + int(c_3[5:], 16)) / 2):02X}"
1243
+ f"#{int((int(fill[1:3], 16) + int(sel_rows_bg[1:3], 16)) / 2):02X}"
1244
+ + f"{int((int(fill[3:5], 16) + int(sel_rows_bg[3:5], 16)) / 2):02X}"
1245
+ + f"{int((int(fill[5:], 16) + int(sel_rows_bg[5:], 16)) / 2):02X}"
1246
1246
  )
1247
1247
  elif "cells" in selections and r in selections["cells"]:
1248
1248
  txtfg = (
@@ -1250,17 +1250,15 @@ class RowIndex(tk.Canvas):
1250
1250
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
1251
1251
  else kwargs[1]
1252
1252
  )
1253
- if kwargs[0] is not None:
1253
+ if fill:
1254
1254
  fill = (
1255
- f"#{int((int(c_1[1:3], 16) + int(c_2[1:3], 16)) / 2):02X}"
1256
- + f"{int((int(c_1[3:5], 16) + int(c_2[3:5], 16)) / 2):02X}"
1257
- + f"{int((int(c_1[5:], 16) + int(c_2[5:], 16)) / 2):02X}"
1255
+ f"#{int((int(fill[1:3], 16) + int(sel_cells_bg[1:3], 16)) / 2):02X}"
1256
+ + f"{int((int(fill[3:5], 16) + int(sel_cells_bg[3:5], 16)) / 2):02X}"
1257
+ + f"{int((int(fill[5:], 16) + int(sel_cells_bg[5:], 16)) / 2):02X}"
1258
1258
  )
1259
1259
  else:
1260
1260
  txtfg = self.PAR.ops.index_fg if kwargs[1] is None else kwargs[1]
1261
- if kwargs[0] is not None:
1262
- fill = kwargs[0]
1263
- if kwargs[0] is not None:
1261
+ if fill:
1264
1262
  redrawn = self.redraw_highlight(
1265
1263
  0,
1266
1264
  fr + 1,
@@ -1592,12 +1590,12 @@ class RowIndex(tk.Canvas):
1592
1590
  )
1593
1591
  )
1594
1592
  self.redraw_gridline(points=points, fill=self.PAR.ops.index_grid_fg, width=1, tag="h")
1595
- c_2 = (
1593
+ sel_cells_bg = (
1596
1594
  self.PAR.ops.index_selected_cells_bg
1597
1595
  if self.PAR.ops.index_selected_cells_bg.startswith("#")
1598
1596
  else color_map[self.PAR.ops.index_selected_cells_bg]
1599
1597
  )
1600
- c_3 = (
1598
+ sel_rows_bg = (
1601
1599
  self.PAR.ops.index_selected_rows_bg
1602
1600
  if self.PAR.ops.index_selected_rows_bg.startswith("#")
1603
1601
  else color_map[self.PAR.ops.index_selected_rows_bg]
@@ -1614,13 +1612,13 @@ class RowIndex(tk.Canvas):
1614
1612
  continue
1615
1613
  datarn = r if self.MT.all_rows_displayed else self.MT.displayed_rows[r]
1616
1614
  fill, tree_arrow_fg, dd_drawn = self.redraw_highlight_get_text_fg(
1617
- rtopgridln,
1618
- rbotgridln,
1619
- r,
1620
- c_2,
1621
- c_3,
1622
- selections,
1623
- datarn,
1615
+ fr=rtopgridln,
1616
+ sr=rbotgridln,
1617
+ r=r,
1618
+ sel_cells_bg=sel_cells_bg,
1619
+ sel_rows_bg=sel_rows_bg,
1620
+ selections=selections,
1621
+ datarn=datarn,
1624
1622
  )
1625
1623
 
1626
1624
  if datarn in self.cell_options and "align" in self.cell_options[datarn]:
@@ -1637,7 +1635,7 @@ class RowIndex(tk.Canvas):
1637
1635
  rtopgridln,
1638
1636
  self.current_width - 1,
1639
1637
  rbotgridln - 1,
1640
- fill=fill,
1638
+ fill=fill if dropdown_kwargs["state"] != "disabled" else self.PAR.ops.index_grid_fg,
1641
1639
  outline=fill,
1642
1640
  tag="dd",
1643
1641
  draw_outline=not dd_drawn,
@@ -1656,7 +1654,7 @@ class RowIndex(tk.Canvas):
1656
1654
  rtopgridln,
1657
1655
  self.current_width - 1,
1658
1656
  rbotgridln - 1,
1659
- fill=fill,
1657
+ fill=fill if dropdown_kwargs["state"] != "disabled" else self.PAR.ops.index_grid_fg,
1660
1658
  outline=fill,
1661
1659
  tag="dd",
1662
1660
  draw_outline=not dd_drawn,
@@ -1676,7 +1674,7 @@ class RowIndex(tk.Canvas):
1676
1674
  rtopgridln,
1677
1675
  self.current_width - 1,
1678
1676
  rbotgridln - 1,
1679
- fill=fill,
1677
+ fill=fill if dropdown_kwargs["state"] != "disabled" else self.PAR.ops.index_grid_fg,
1680
1678
  outline=fill,
1681
1679
  tag="dd",
1682
1680
  draw_outline=not dd_drawn,
@@ -2148,21 +2146,43 @@ class RowIndex(tk.Canvas):
2148
2146
 
2149
2147
  def dropdown_text_editor_modified(
2150
2148
  self,
2151
- dd_window: object,
2152
- event: dict,
2153
- modified_func: Callable | None,
2149
+ event: tk.Misc,
2154
2150
  ) -> None:
2155
- if modified_func:
2156
- modified_func(event)
2157
- dd_window.search_and_see(event)
2151
+ r = self.dropdown.get_coords()
2152
+ event_data = event_dict(
2153
+ name="table_dropdown_modified",
2154
+ sheet=self.PAR.name,
2155
+ value=self.text_editor.get(),
2156
+ loc=r,
2157
+ row=r,
2158
+ column=0,
2159
+ boxes=self.MT.get_boxes(),
2160
+ selected=self.MT.selected,
2161
+ )
2162
+ try_binding(self.dropdown.window.modified_function, event_data)
2163
+ val = self.dropdown.window.search_and_see(event_data)
2164
+ # return to tk.Text action if control/command is held down
2165
+ # or keysym was not a character
2166
+ if (hasattr(event, "state") and event.state & (0x0004 | 0x00000010)) or (
2167
+ hasattr(event, "keysym") and len(event.keysym) > 2
2168
+ ):
2169
+ return
2170
+ self.text_editor.tktext.unbind("<KeyRelease>")
2171
+ self.text_editor.autocomplete(val)
2172
+ self.text_editor.tktext.bind(
2173
+ "<KeyRelease>",
2174
+ self.dropdown_text_editor_modified,
2175
+ )
2176
+ return "break"
2158
2177
 
2159
2178
  # r is displayed row
2160
2179
  def open_dropdown_window(self, r: int, event: object = None) -> None:
2161
2180
  self.hide_text_editor()
2162
2181
  kwargs = self.get_cell_kwargs(self.MT.datarn(r), key="dropdown")
2163
- if kwargs["state"] == "normal":
2164
- if not self.open_text_editor(event=event, r=r, dropdown=True):
2165
- return
2182
+ if kwargs["state"] == "disabled":
2183
+ return
2184
+ if kwargs["state"] == "normal" and not self.open_text_editor(event=event, r=r, dropdown=True):
2185
+ return
2166
2186
  win_h, anchor = self.get_dropdown_height_anchor(r)
2167
2187
  win_w = self.current_width + 1
2168
2188
  if anchor == "nw":
@@ -2183,6 +2203,8 @@ class RowIndex(tk.Canvas):
2183
2203
  "outline_color": self.PAR.ops.index_selected_rows_bg,
2184
2204
  "align": self.get_cell_align(r),
2185
2205
  "values": kwargs["values"],
2206
+ "search_function": kwargs["search_function"],
2207
+ "modified_function": kwargs["modified_function"],
2186
2208
  }
2187
2209
  if self.dropdown.window:
2188
2210
  self.dropdown.window.reset(**reset_kwargs)
@@ -2195,7 +2217,6 @@ class RowIndex(tk.Canvas):
2195
2217
  **reset_kwargs,
2196
2218
  single_index="r",
2197
2219
  close_dropdown_window=self.close_dropdown_window,
2198
- search_function=kwargs["search_function"],
2199
2220
  arrowkey_RIGHT=self.MT.arrowkey_RIGHT,
2200
2221
  arrowkey_LEFT=self.MT.arrowkey_LEFT,
2201
2222
  )
@@ -2206,20 +2227,8 @@ class RowIndex(tk.Canvas):
2206
2227
  )
2207
2228
  if kwargs["state"] == "normal":
2208
2229
  self.text_editor.tktext.bind(
2209
- "<<TextModified>>",
2210
- lambda _x: self.dropdown_text_editor_modified(
2211
- self.dropdown.window,
2212
- event_dict(
2213
- name="index_dropdown_modified",
2214
- sheet=self.PAR.name,
2215
- value=self.text_editor.get(),
2216
- loc=r,
2217
- row=r,
2218
- boxes=self.MT.get_boxes(),
2219
- selected=self.MT.selected,
2220
- ),
2221
- kwargs["modified_function"],
2222
- ),
2230
+ "<KeyRelease>",
2231
+ self.dropdown_text_editor_modified,
2223
2232
  )
2224
2233
  self.update_idletasks()
2225
2234
  try:
@@ -607,6 +607,46 @@ class Sheet(tk.Frame):
607
607
  # Bindings and Functionality
608
608
 
609
609
  def enable_bindings(self, *bindings: str) -> Sheet:
610
+ """
611
+ List of available bindings:
612
+ - "all"
613
+ - "single_select"
614
+ - "toggle_select"
615
+ - "drag_select"
616
+ - "select_all"
617
+ - "column_drag_and_drop" / "move_columns"
618
+ - "row_drag_and_drop" / "move_rows"
619
+ - "column_select"
620
+ - "row_select"
621
+ - "column_width_resize"
622
+ - "double_click_column_resize"
623
+ - "row_width_resize"
624
+ - "column_height_resize"
625
+ - "arrowkeys" # all arrowkeys including page up and down
626
+ - "up"
627
+ - "down"
628
+ - "left"
629
+ - "right"
630
+ - "prior" # page up
631
+ - "next" # page down
632
+ - "row_height_resize"
633
+ - "double_click_row_resize"
634
+ - "right_click_popup_menu" / "rc_popup_menu" / "rc_menu"
635
+ - "rc_select"
636
+ - "rc_insert_column"
637
+ - "rc_delete_column"
638
+ - "rc_insert_row"
639
+ - "rc_delete_row"
640
+ - "ctrl_click_select" / "ctrl_select"
641
+ - "copy"
642
+ - "cut"
643
+ - "paste"
644
+ - "delete"
645
+ - "undo"
646
+ - "edit_cell"
647
+ - "edit_header"
648
+ - "edit_index"
649
+ """
610
650
  self.MT.enable_bindings(bindings)
611
651
  return self
612
652
 
@@ -619,6 +659,57 @@ class Sheet(tk.Frame):
619
659
  bindings: str | list | tuple | None = None,
620
660
  func: Callable | None = None,
621
661
  ) -> Sheet:
662
+ """
663
+ List of available bindings:
664
+ - "begin_copy", "begin_ctrl_c"
665
+ - "ctrl_c", "end_copy", "end_ctrl_c", "copy"
666
+ - "begin_cut", "begin_ctrl_x"
667
+ - "ctrl_x", "end_cut", "end_ctrl_x", "cut"
668
+ - "begin_paste", "begin_ctrl_v"
669
+ - "ctrl_v", "end_paste", "end_ctrl_v", "paste"
670
+ - "begin_undo", "begin_ctrl_z"
671
+ - "ctrl_z", "end_undo", "end_ctrl_z", "undo"
672
+ - "begin_delete_key", "begin_delete"
673
+ - "delete_key", "end_delete", "end_delete_key", "delete"
674
+ - "begin_edit_cell", "begin_edit_table"
675
+ - "end_edit_cell", "edit_cell", "edit_table"
676
+ - "begin_edit_header"
677
+ - "end_edit_header", "edit_header"
678
+ - "begin_edit_index"
679
+ - "end_edit_index", "edit_index"
680
+ - "begin_row_index_drag_drop", "begin_move_rows"
681
+ - "row_index_drag_drop", "move_rows", "end_move_rows", "end_row_index_drag_drop"
682
+ - "begin_column_header_drag_drop", "begin_move_columns"
683
+ - "column_header_drag_drop", "move_columns", "end_move_columns", "end_column_header_drag_drop"
684
+ - "begin_rc_delete_row", "begin_delete_rows"
685
+ - "rc_delete_row", "end_rc_delete_row", "end_delete_rows", "delete_rows"
686
+ - "begin_rc_delete_column", "begin_delete_columns"
687
+ - "rc_delete_column", "end_rc_delete_column","end_delete_columns", "delete_columns"
688
+ - "begin_rc_insert_column", "begin_insert_column", "begin_insert_columns", "begin_add_column","begin_rc_add_column", "begin_add_columns"
689
+ - "rc_insert_column", "end_rc_insert_column", "end_insert_column", "end_insert_columns", "rc_add_column", "end_rc_add_column", "end_add_column", "end_add_columns"
690
+ - "begin_rc_insert_row", "begin_insert_row", "begin_insert_rows", "begin_rc_add_row", "begin_add_row", "begin_add_rows"
691
+ - "rc_insert_row", "end_rc_insert_row", "end_insert_row", "end_insert_rows", "rc_add_row", "end_rc_add_row", "end_add_row", "end_add_rows"
692
+ - "row_height_resize"
693
+ - "column_width_resize"
694
+ - "cell_select"
695
+ - "select_all"
696
+ - "row_select"
697
+ - "column_select"
698
+ - "drag_select_cells"
699
+ - "drag_select_rows"
700
+ - "drag_select_columns"
701
+ - "shift_cell_select"
702
+ - "shift_row_select"
703
+ - "shift_column_select"
704
+ - "ctrl_cell_select"
705
+ - "ctrl_row_select"
706
+ - "ctrl_column_select"
707
+ - "deselect"
708
+ - "all_select_events", "select", "selectevents", "select_events"
709
+ - "all_modified_events", "sheetmodified", "sheet_modified" "modified_events", "modified"
710
+ - "bind_all"
711
+ - "unbind_all"
712
+ """
622
713
  # bindings is None, unbind all
623
714
  if bindings is None:
624
715
  bindings = "all"
@@ -2564,7 +2655,7 @@ class Sheet(tk.Frame):
2564
2655
  edit_data: bool = True,
2565
2656
  set_values: dict[tuple[int, int], object] = {},
2566
2657
  set_value: object = None,
2567
- state: str = "normal",
2658
+ state: Literal["normal", "readonly", "disabled"] = "normal",
2568
2659
  redraw: bool = True,
2569
2660
  selection_function: Callable | None = None,
2570
2661
  modified_function: Callable | None = None,
@@ -2675,7 +2766,7 @@ class Sheet(tk.Frame):
2675
2766
  *key: CreateSpanTypes,
2676
2767
  edit_data: bool = True,
2677
2768
  checked: bool | None = None,
2678
- state: str = "normal",
2769
+ state: Literal["normal", "disabled"] = "normal",
2679
2770
  redraw: bool = True,
2680
2771
  check_function: Callable | None = None,
2681
2772
  text: str = "",
@@ -5477,7 +5568,7 @@ class Sheet(tk.Frame):
5477
5568
  def selection_add(self, *items, run_binding: bool = True, redraw: bool = True) -> Sheet:
5478
5569
  to_open = []
5479
5570
  quick_displayed_check = set(self.MT.displayed_rows)
5480
- for item in unpack(items):
5571
+ for item in filter(self.RI.tree.__contains__, unpack(items)):
5481
5572
  if self.RI.tree_rns[item] not in quick_displayed_check and self.RI.tree[item].parent:
5482
5573
  to_open.extend(list(self.RI.get_iid_ancestors(item)))
5483
5574
  if to_open:
@@ -5492,7 +5583,7 @@ class Sheet(tk.Frame):
5492
5583
  self.MT.displayed_rows,
5493
5584
  self.RI.tree_rns[item],
5494
5585
  )
5495
- for item in unpack(items)
5586
+ for item in filter(self.RI.tree.__contains__, unpack(items))
5496
5587
  )
5497
5588
  ):
5498
5589
  self.MT.create_selection_box(
@@ -7067,6 +7158,7 @@ class Dropdown(Sheet):
7067
7158
  values: list[object] = [],
7068
7159
  close_dropdown_window: Callable | None = None,
7069
7160
  search_function: Callable = dropdown_search_function,
7161
+ modified_function: None | Callable = None,
7070
7162
  arrowkey_RIGHT: Callable | None = None,
7071
7163
  arrowkey_LEFT: Callable | None = None,
7072
7164
  align: str = "w",
@@ -7096,6 +7188,7 @@ class Dropdown(Sheet):
7096
7188
  self.parent = parent
7097
7189
  self.close_dropdown_window = close_dropdown_window
7098
7190
  self.search_function = search_function
7191
+ self.modified_function = modified_function
7099
7192
  self.arrowkey_RIGHT = arrowkey_RIGHT
7100
7193
  self.arrowkey_LEFT = arrowkey_LEFT
7101
7194
  self.single_index = single_index
@@ -7122,11 +7215,15 @@ class Dropdown(Sheet):
7122
7215
  outline_color: str,
7123
7216
  align: str,
7124
7217
  values: list[object] | None = None,
7218
+ search_function: Callable = dropdown_search_function,
7219
+ modified_function: None | Callable = None,
7125
7220
  ) -> None:
7126
7221
  self.deselect(redraw=False)
7127
7222
  self.r = r
7128
7223
  self.c = c
7129
7224
  self.row = -1
7225
+ self.search_function = search_function
7226
+ self.modified_function = modified_function
7130
7227
  self.height_and_width(height=height, width=width)
7131
7228
  self.table_align(align)
7132
7229
  self.set_options(
@@ -7160,13 +7257,14 @@ class Dropdown(Sheet):
7160
7257
  self.see(self.row, 0, redraw=False)
7161
7258
  self.select_row(self.row)
7162
7259
 
7163
- def search_and_see(self, event: object = None) -> None:
7260
+ def search_and_see(self, event: object = None) -> str:
7164
7261
  if self.search_function is not None:
7165
7262
  rn = self.search_function(search_for=rf"{event['value']}".lower(), data=self.MT.data)
7166
- if rn is not None:
7263
+ if isinstance(rn, int):
7167
7264
  self.row = rn
7168
7265
  self.see(self.row, 0, redraw=False)
7169
7266
  self.select_row(self.row)
7267
+ return self.MT.data[rn][0]
7170
7268
 
7171
7269
  def mouse_motion(self, event: object) -> None:
7172
7270
  row = self.identify_row(event, exclude_index=True, allow_end=False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tksheet
3
- Version: 7.2.21
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
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes