tksheet 7.5.10__py3-none-any.whl → 7.5.12__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/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
  tksheet - A Python tkinter table widget
5
5
  """
6
6
 
7
- __version__ = "7.5.10"
7
+ __version__ = "7.5.12"
8
8
 
9
9
  from .colors import (
10
10
  color_map,
tksheet/column_headers.py CHANGED
@@ -20,6 +20,7 @@ from .constants import (
20
20
  )
21
21
  from .formatters import is_bool_like, try_to_bool
22
22
  from .functions import (
23
+ any_editor_or_dropdown_open,
23
24
  consecutive_ranges,
24
25
  event_dict,
25
26
  event_has_char_key,
@@ -49,7 +50,7 @@ from .tooltip import Tooltip
49
50
 
50
51
 
51
52
  class ColumnHeaders(tk.Canvas):
52
- def __init__(self, parent, **kwargs):
53
+ def __init__(self, parent: tk.Misc, **kwargs) -> None:
53
54
  super().__init__(
54
55
  parent,
55
56
  background=parent.ops.header_bg,
@@ -72,6 +73,7 @@ class ColumnHeaders(tk.Canvas):
72
73
  )
73
74
  self.tooltip_widgets = widget_descendants(self.tooltip)
74
75
  self.tooltip_coords, self.tooltip_after_id, self.tooltip_showing = None, None, False
76
+ self.tooltip_cell_content = ""
75
77
  recursive_bind(self.tooltip, "<Leave>", self.close_tooltip_save)
76
78
  self.current_cursor = ""
77
79
  self.popup_menu_loc = None
@@ -1268,6 +1270,7 @@ class ColumnHeaders(tk.Canvas):
1268
1270
  selections: dict,
1269
1271
  datacn: int,
1270
1272
  has_dd: bool,
1273
+ tags: str | tuple[str],
1271
1274
  ) -> tuple[str, bool]:
1272
1275
  redrawn = False
1273
1276
  kwargs = self.get_cell_kwargs(datacn, key="highlight")
@@ -1294,6 +1297,7 @@ class ColumnHeaders(tk.Canvas):
1294
1297
  + f"{int((int(high_bg[5:], 16) + int(sel_cols_bg[5:], 16)) / 2):02X}"
1295
1298
  ),
1296
1299
  outline=self.ops.header_fg if has_dd and self.ops.show_dropdown_borders else "",
1300
+ tags=tags,
1297
1301
  )
1298
1302
  elif "cells" in selections and c in selections["cells"]:
1299
1303
  txtfg = (
@@ -1314,6 +1318,7 @@ class ColumnHeaders(tk.Canvas):
1314
1318
  + f"{int((int(high_bg[5:], 16) + int(sel_cells_bg[5:], 16)) / 2):02X}"
1315
1319
  ),
1316
1320
  outline=self.ops.header_fg if has_dd and self.ops.show_dropdown_borders else "",
1321
+ tags=tags,
1317
1322
  )
1318
1323
  else:
1319
1324
  txtfg = self.ops.header_fg if kwargs[1] is None else kwargs[1]
@@ -1325,6 +1330,7 @@ class ColumnHeaders(tk.Canvas):
1325
1330
  self.current_height - 1,
1326
1331
  fill=high_bg,
1327
1332
  outline=self.ops.header_fg if has_dd and self.ops.show_dropdown_borders else "",
1333
+ tags=tags,
1328
1334
  )
1329
1335
  elif not kwargs:
1330
1336
  if "columns" in selections and c in selections["columns"]:
@@ -1336,6 +1342,7 @@ class ColumnHeaders(tk.Canvas):
1336
1342
  self.current_height - 1,
1337
1343
  fill=self.ops.header_selected_columns_bg,
1338
1344
  outline=self.ops.header_fg if has_dd and self.ops.show_dropdown_borders else "",
1345
+ tags=tags,
1339
1346
  )
1340
1347
  elif "cells" in selections and c in selections["cells"]:
1341
1348
  txtfg = self.ops.header_selected_cells_fg
@@ -1346,9 +1353,19 @@ class ColumnHeaders(tk.Canvas):
1346
1353
  self.current_height - 1,
1347
1354
  fill=self.ops.header_selected_cells_bg,
1348
1355
  outline=self.ops.header_fg if has_dd and self.ops.show_dropdown_borders else "",
1356
+ tags=tags,
1349
1357
  )
1350
1358
  else:
1351
1359
  txtfg = self.ops.header_fg
1360
+ redrawn = self.redraw_highlight(
1361
+ fc + 1,
1362
+ 0,
1363
+ sc,
1364
+ self.current_height - 1,
1365
+ fill="",
1366
+ outline=self.ops.header_fg if has_dd and self.ops.show_dropdown_borders else "",
1367
+ tags=tags,
1368
+ )
1352
1369
  return txtfg, redrawn
1353
1370
 
1354
1371
  def redraw_highlight(
@@ -1359,17 +1376,18 @@ class ColumnHeaders(tk.Canvas):
1359
1376
  y2: float,
1360
1377
  fill: str,
1361
1378
  outline: str,
1379
+ tags: str | tuple[str],
1362
1380
  ) -> bool:
1363
1381
  coords = (x1, y1, x2, y2)
1364
1382
  if self.hidd_high:
1365
1383
  iid, showing = self.hidd_high.popitem()
1366
1384
  self.coords(iid, coords)
1367
1385
  if showing:
1368
- self.itemconfig(iid, fill=fill, outline=outline)
1386
+ self.itemconfig(iid, fill=fill, outline=outline, tags=tags)
1369
1387
  else:
1370
- self.itemconfig(iid, fill=fill, outline=outline, state="normal")
1388
+ self.itemconfig(iid, fill=fill, outline=outline, state="normal", tags=tags)
1371
1389
  else:
1372
- iid = self.create_rectangle(coords, fill=fill, outline=outline)
1390
+ iid = self.create_rectangle(coords, fill=fill, outline=outline, tags=tags)
1373
1391
  self.disp_high[iid] = True
1374
1392
  return True
1375
1393
 
@@ -1402,8 +1420,8 @@ class ColumnHeaders(tk.Canvas):
1402
1420
  draw_arrow: bool = True,
1403
1421
  open_: bool = False,
1404
1422
  ) -> None:
1405
- if draw_outline and self.ops.show_dropdown_borders:
1406
- self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.ops.header_fg)
1423
+ # if draw_outline and self.ops.show_dropdown_borders:
1424
+ # self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.ops.header_fg)
1407
1425
  if draw_arrow:
1408
1426
  mod = (self.MT.header_txt_height - 1) if self.MT.header_txt_height % 2 else self.MT.header_txt_height
1409
1427
  small_mod = int(mod / 5)
@@ -1506,15 +1524,15 @@ class ColumnHeaders(tk.Canvas):
1506
1524
  self.MT.char_widths[self.header_font][c] = wd
1507
1525
  return wd
1508
1526
 
1509
- def redraw_corner(self, x: float, y: float) -> None:
1527
+ def redraw_corner(self, x: float, y: float, tags: str | tuple[str]) -> None:
1510
1528
  if self.hidd_corners:
1511
1529
  iid = self.hidd_corners.pop()
1512
1530
  self.coords(iid, x - 10, y, x, y, x, y + 10)
1513
- self.itemconfig(iid, fill=self.ops.header_grid_fg, state="normal")
1531
+ self.itemconfig(iid, fill=self.ops.header_grid_fg, state="normal", tags=tags)
1514
1532
  self.disp_corners.add(iid)
1515
1533
  else:
1516
1534
  self.disp_corners.add(
1517
- self.create_polygon(x - 10, y, x, y, x, y + 10, fill=self.ops.header_grid_fg, tags="lift")
1535
+ self.create_polygon(x - 10, y, x, y, x, y + 10, fill=self.ops.header_grid_fg, tags=tags)
1518
1536
  )
1519
1537
 
1520
1538
  def redraw_grid_and_text(
@@ -1552,7 +1570,6 @@ class ColumnHeaders(tk.Canvas):
1552
1570
  self.current_height,
1553
1571
  )
1554
1572
  top = self.canvasy(0)
1555
-
1556
1573
  if (self.ops.show_vertical_grid or self.width_resizing_enabled) and col_pos_exists:
1557
1574
  yend = self.current_height - 5
1558
1575
  points = [
@@ -1580,7 +1597,6 @@ class ColumnHeaders(tk.Canvas):
1580
1597
  )
1581
1598
  )
1582
1599
  self.redraw_gridline(points=points, fill=self.ops.header_grid_fg, width=1)
1583
-
1584
1600
  sel_cells_bg = (
1585
1601
  self.ops.header_selected_cells_bg
1586
1602
  if self.ops.header_selected_cells_bg.startswith("#")
@@ -1603,6 +1619,7 @@ class ColumnHeaders(tk.Canvas):
1603
1619
  crightgridln = self.MT.col_positions[c + 1]
1604
1620
  datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
1605
1621
  kwargs = self.get_cell_kwargs(datacn, key="dropdown")
1622
+ tag = f"{c}"
1606
1623
  fill, dd_drawn = self.redraw_highlight_get_text_fg(
1607
1624
  fc=cleftgridln,
1608
1625
  sc=crightgridln,
@@ -1612,6 +1629,7 @@ class ColumnHeaders(tk.Canvas):
1612
1629
  selections=selections,
1613
1630
  datacn=datacn,
1614
1631
  has_dd=bool(kwargs),
1632
+ tags=("h", "c", tag),
1615
1633
  )
1616
1634
  if datacn in self.cell_options and "align" in self.cell_options[datacn]:
1617
1635
  align = self.cell_options[datacn]["align"]
@@ -1675,10 +1693,9 @@ class ColumnHeaders(tk.Canvas):
1675
1693
  or (align[-1] == "n" and cleftgridln + 5 > scrollpos_right)
1676
1694
  ):
1677
1695
  continue
1678
-
1696
+ tags = ("lift", "c", tag)
1679
1697
  if note_corners and max_width > 5 and datacn in self.cell_options and "note" in self.cell_options[datacn]:
1680
- self.redraw_corner(crightgridln, 0)
1681
-
1698
+ self.redraw_corner(crightgridln, 0, tags)
1682
1699
  text = self.cell_str(datacn, fix=False)
1683
1700
  if not text:
1684
1701
  continue
@@ -1701,7 +1718,7 @@ class ColumnHeaders(tk.Canvas):
1701
1718
  fill=fill,
1702
1719
  font=font,
1703
1720
  anchor=align,
1704
- tags=("lift", "t", f"{c}"),
1721
+ tags=tags,
1705
1722
  )
1706
1723
  else:
1707
1724
  self.itemconfig(
@@ -1711,7 +1728,7 @@ class ColumnHeaders(tk.Canvas):
1711
1728
  font=font,
1712
1729
  anchor=align,
1713
1730
  state="normal",
1714
- tags=("lift", "t", f"{c}"),
1731
+ tags=tags,
1715
1732
  )
1716
1733
  else:
1717
1734
  iid = self.create_text(
@@ -1721,7 +1738,7 @@ class ColumnHeaders(tk.Canvas):
1721
1738
  fill=fill,
1722
1739
  font=font,
1723
1740
  anchor=align,
1724
- tags=("lift", "t", f"{c}"),
1741
+ tags=tags,
1725
1742
  )
1726
1743
  self.disp_text[iid] = True
1727
1744
  else:
@@ -1736,7 +1753,7 @@ class ColumnHeaders(tk.Canvas):
1736
1753
  fill=fill,
1737
1754
  font=font,
1738
1755
  anchor=align,
1739
- tags=("lift", "t", f"{c}"),
1756
+ tags=tags,
1740
1757
  )
1741
1758
  else:
1742
1759
  self.itemconfig(
@@ -1746,7 +1763,7 @@ class ColumnHeaders(tk.Canvas):
1746
1763
  font=font,
1747
1764
  anchor=align,
1748
1765
  state="normal",
1749
- tags=("lift", "t", f"{c}"),
1766
+ tags=tags,
1750
1767
  )
1751
1768
  else:
1752
1769
  iid = self.create_text(
@@ -1756,7 +1773,7 @@ class ColumnHeaders(tk.Canvas):
1756
1773
  fill=fill,
1757
1774
  font=font,
1758
1775
  anchor=align,
1759
- tags=("lift", "t", f"{c}"),
1776
+ tags=tags,
1760
1777
  )
1761
1778
  self.disp_text[iid] = True
1762
1779
  draw_y += self.MT.header_txt_height
@@ -1771,12 +1788,12 @@ class ColumnHeaders(tk.Canvas):
1771
1788
  self.tag_raise("lift")
1772
1789
  if self.disp_resize_lines:
1773
1790
  self.tag_raise("rw")
1774
- self.tag_bind("t", "<Enter>", self.enter_text)
1775
- self.tag_bind("t", "<Leave>", self.leave_text)
1791
+ self.tag_bind("c", "<Enter>", self.enter_cell)
1792
+ self.tag_bind("c", "<Leave>", self.leave_cell)
1776
1793
  return True
1777
1794
 
1778
- def enter_text(self, event: tk.Event | None = None) -> None:
1779
- if self.text_editor.open or self.dropdown.open:
1795
+ def enter_cell(self, event: tk.Event | None = None) -> None:
1796
+ if any_editor_or_dropdown_open(self.MT):
1780
1797
  return
1781
1798
  can_x, can_y = self.canvasx(event.x), self.canvasy(event.y)
1782
1799
  for i in self.find_overlapping(can_x - 1, can_y - 1, can_x + 1, can_y + 1):
@@ -1790,7 +1807,7 @@ class ColumnHeaders(tk.Canvas):
1790
1807
  except Exception:
1791
1808
  continue
1792
1809
 
1793
- def leave_text(self, event: tk.Event | None = None) -> None:
1810
+ def leave_cell(self, event: tk.Event | None = None) -> None:
1794
1811
  if self.tooltip_after_id is not None:
1795
1812
  self.after_cancel(self.tooltip_after_id)
1796
1813
  self.tooltip_after_id = None
@@ -1801,7 +1818,7 @@ class ColumnHeaders(tk.Canvas):
1801
1818
  self.tooltip_coords = None
1802
1819
 
1803
1820
  def start_tooltip_timer(self) -> None:
1804
- self.tooltip_after_id = self.after(1000, self.check_and_show_tooltip)
1821
+ self.tooltip_after_id = self.after(self.ops.tooltip_hover_delay, self.check_and_show_tooltip)
1805
1822
 
1806
1823
  def check_and_show_tooltip(self, event: tk.Event | None = None) -> None:
1807
1824
  current_x, current_y = self.winfo_pointerx(), self.winfo_pointery()
@@ -1823,19 +1840,22 @@ class ColumnHeaders(tk.Canvas):
1823
1840
  kws = self.get_cell_kwargs(datacn, key="note")
1824
1841
  if not self.ops.tooltips and not kws and not self.ops.user_can_create_notes:
1825
1842
  return
1843
+ self.MT.hide_tooltip()
1844
+ self.RI.hide_tooltip()
1826
1845
  cell_readonly = self.get_cell_kwargs(datacn, "readonly") or not self.MT.index_edit_cell_enabled()
1827
1846
  if kws:
1828
1847
  note = kws["note"]
1829
1848
  note_readonly = kws["readonly"]
1830
1849
  elif self.ops.user_can_create_notes:
1831
1850
  note = ""
1832
- note_readonly = bool(cell_readonly)
1851
+ note_readonly = False
1833
1852
  else:
1834
1853
  note = None
1835
1854
  note_readonly = True
1855
+ self.tooltip_cell_content = f"{self.get_cell_data(datacn, none_to_empty_str=True)}"
1836
1856
  self.tooltip.reset(
1837
1857
  **{
1838
- "text": f"{self.get_cell_data(datacn, none_to_empty_str=True)}",
1858
+ "text": self.tooltip_cell_content,
1839
1859
  "cell_readonly": cell_readonly,
1840
1860
  "note": note,
1841
1861
  "note_readonly": note_readonly,
@@ -1855,25 +1875,18 @@ class ColumnHeaders(tk.Canvas):
1855
1875
  def close_tooltip_save(self, event: tk.Event | None = None) -> None:
1856
1876
  widget = self.winfo_containing(self.winfo_pointerx(), self.winfo_pointery())
1857
1877
  if any(widget == tw for tw in self.tooltip_widgets):
1858
- try:
1859
- if self.tooltip.notebook.index("current") == 0:
1860
- self.tooltip.content_text.focus_set()
1861
- else:
1862
- self.tooltip.note_text.focus_set()
1863
- except Exception:
1864
- self.tooltip.content_text.focus_set()
1865
1878
  return
1866
1879
  if not self.tooltip.cell_readonly or not self.tooltip.note_readonly:
1867
1880
  _, c, cell, note = self.tooltip.get()
1868
1881
  datacn = self.MT.datacn(c)
1869
- if not self.tooltip.cell_readonly:
1882
+ if not self.tooltip.cell_readonly and cell != self.tooltip_cell_content:
1870
1883
  event_data = self.new_single_edit_event(c, datacn, "??", self.get_cell_data(datacn), cell)
1871
1884
  self.do_single_edit(c, datacn, event_data, cell)
1872
1885
  if not self.tooltip.note_readonly:
1873
1886
  span = self.PAR.span(None, datacn, None, datacn + 1).options(table=False, header=True)
1874
1887
  self.PAR.note(span, note=note if note else None, readonly=False)
1888
+ self.MT.refresh()
1875
1889
  self.hide_tooltip()
1876
- self.MT.refresh()
1877
1890
  self.focus_set()
1878
1891
 
1879
1892
  def get_redraw_selections(self, startc: int, endc: int) -> dict[str, set[int]]:
@@ -1960,6 +1973,7 @@ class ColumnHeaders(tk.Canvas):
1960
1973
  self.text_editor.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
1961
1974
  return False
1962
1975
  self.hide_text_editor()
1976
+ self.hide_tooltip()
1963
1977
  if not self.MT.see(0, c, keep_yscroll=True):
1964
1978
  self.MT.main_table_redraw_grid_and_text(True, True)
1965
1979
  x = self.MT.col_positions[c] + 1
tksheet/functions.py CHANGED
@@ -841,11 +841,21 @@ def remove_duplicates_outside_section(strings: list[str], section_start: int, se
841
841
 
842
842
  section_end = section_start + section_size
843
843
  section_set = set(strings[section_start:section_end])
844
- print(section_set, section_start, section_size)
845
844
 
846
845
  return [s for i, s in enumerate(strings) if (section_start <= i < section_end) or (s not in section_set)]
847
846
 
848
847
 
848
+ def any_editor_or_dropdown_open(MT) -> bool:
849
+ return (
850
+ MT.dropdown.open
851
+ or MT.RI.dropdown.open
852
+ or MT.CH.dropdown.open
853
+ or MT.text_editor.open
854
+ or MT.RI.text_editor.open
855
+ or MT.CH.text_editor.open
856
+ )
857
+
858
+
849
859
  def get_new_indexes(
850
860
  move_to: int,
851
861
  to_move: Iterable[int],
tksheet/main_table.py CHANGED
@@ -41,6 +41,7 @@ from .formatters import (
41
41
  )
42
42
  from .functions import (
43
43
  add_to_displayed,
44
+ any_editor_or_dropdown_open,
44
45
  b_index,
45
46
  bisect_in,
46
47
  box_gen_coords,
@@ -113,11 +114,11 @@ from .tooltip import Tooltip
113
114
  class MainTable(tk.Canvas):
114
115
  def __init__(
115
116
  self,
116
- parent,
117
+ parent: tk.Misc,
117
118
  row_index_canvas: RowIndex,
118
119
  column_headers_canvas: ColumnHeaders,
119
120
  **kwargs,
120
- ):
121
+ ) -> None:
121
122
  super().__init__(
122
123
  parent,
123
124
  background=parent.ops.table_bg,
@@ -148,6 +149,7 @@ class MainTable(tk.Canvas):
148
149
  )
149
150
  self.tooltip_widgets = widget_descendants(self.tooltip)
150
151
  self.tooltip_coords, self.tooltip_after_id, self.tooltip_showing = None, None, False
152
+ self.tooltip_cell_content = ""
151
153
  recursive_bind(self.tooltip, "<Leave>", self.close_tooltip_save)
152
154
  self.dropdown = DropdownStorage()
153
155
  self.text_editor = TextEditorStorage()
@@ -5695,7 +5697,8 @@ class MainTable(tk.Canvas):
5695
5697
  can_width: int | None,
5696
5698
  dont_blend: bool,
5697
5699
  alternate_color: Highlight | None,
5698
- has_dd: bool = False,
5700
+ has_dd: bool,
5701
+ tags: str | tuple[str],
5699
5702
  ) -> tuple[str, bool]:
5700
5703
  redrawn = False
5701
5704
  if (datarn, datacn) in self.progress_bars:
@@ -5745,6 +5748,7 @@ class MainTable(tk.Canvas):
5745
5748
  )
5746
5749
  ),
5747
5750
  outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5751
+ tags=tags,
5748
5752
  can_width=None,
5749
5753
  pc=None,
5750
5754
  )
@@ -5771,6 +5775,7 @@ class MainTable(tk.Canvas):
5771
5775
  )
5772
5776
  ),
5773
5777
  outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5778
+ tags=tags,
5774
5779
  can_width=None,
5775
5780
  pc=None,
5776
5781
  )
@@ -5797,6 +5802,7 @@ class MainTable(tk.Canvas):
5797
5802
  )
5798
5803
  ),
5799
5804
  outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5805
+ tags=tags,
5800
5806
  can_width=None,
5801
5807
  pc=None,
5802
5808
  )
@@ -5813,6 +5819,7 @@ class MainTable(tk.Canvas):
5813
5819
  y2=sr,
5814
5820
  fill=high_bg,
5815
5821
  outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5822
+ tags=tags,
5816
5823
  can_width=can_width if (len(kwargs) > 2 and kwargs[2]) else None,
5817
5824
  pc=None,
5818
5825
  )
@@ -5827,6 +5834,7 @@ class MainTable(tk.Canvas):
5827
5834
  y2=sr,
5828
5835
  fill=high_bg,
5829
5836
  outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5837
+ tags=tags,
5830
5838
  can_width=None,
5831
5839
  pc=kwargs.percent,
5832
5840
  )
@@ -5841,6 +5849,7 @@ class MainTable(tk.Canvas):
5841
5849
  y2=sr,
5842
5850
  fill=self.PAR.ops.table_selected_cells_bg,
5843
5851
  outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5852
+ tags=tags,
5844
5853
  can_width=None,
5845
5854
  pc=None,
5846
5855
  )
@@ -5853,6 +5862,7 @@ class MainTable(tk.Canvas):
5853
5862
  y2=sr,
5854
5863
  fill=self.PAR.ops.table_selected_rows_bg,
5855
5864
  outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5865
+ tags=tags,
5856
5866
  can_width=None,
5857
5867
  pc=None,
5858
5868
  )
@@ -5865,11 +5875,23 @@ class MainTable(tk.Canvas):
5865
5875
  y2=sr,
5866
5876
  fill=self.PAR.ops.table_selected_columns_bg,
5867
5877
  outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5878
+ tags=tags,
5868
5879
  can_width=None,
5869
5880
  pc=None,
5870
5881
  )
5871
5882
  else:
5872
5883
  txtfg = self.PAR.ops.table_fg
5884
+ redrawn = self.redraw_highlight(
5885
+ x1=fc + 1,
5886
+ y1=fr + 1,
5887
+ x2=sc,
5888
+ y2=sr,
5889
+ fill="",
5890
+ outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5891
+ tags=tags,
5892
+ can_width=None,
5893
+ pc=None,
5894
+ )
5873
5895
  return txtfg, redrawn
5874
5896
 
5875
5897
  def redraw_highlight(
@@ -5880,6 +5902,7 @@ class MainTable(tk.Canvas):
5880
5902
  y2: int | float,
5881
5903
  fill: str,
5882
5904
  outline: str,
5905
+ tags: str | tuple[str],
5883
5906
  can_width: None | float = None,
5884
5907
  pc: None | float = None,
5885
5908
  ) -> bool:
@@ -5898,11 +5921,11 @@ class MainTable(tk.Canvas):
5898
5921
  iid, showing = self.hidd_high.popitem()
5899
5922
  self.coords(iid, coords)
5900
5923
  if showing:
5901
- self.itemconfig(iid, fill=fill, outline=outline)
5924
+ self.itemconfig(iid, fill=fill, outline=outline, tags=tags)
5902
5925
  else:
5903
- self.itemconfig(iid, fill=fill, outline=outline, state="normal")
5926
+ self.itemconfig(iid, fill=fill, outline=outline, state="normal", tags=tags)
5904
5927
  else:
5905
- iid = self.create_rectangle(coords, fill=fill, outline=outline)
5928
+ iid = self.create_rectangle(coords, fill=fill, outline=outline, tags=tags)
5906
5929
  self.disp_high[iid] = True
5907
5930
  return True
5908
5931
 
@@ -6083,15 +6106,15 @@ class MainTable(tk.Canvas):
6083
6106
  self.char_widths[self.table_font][c] = wd
6084
6107
  return wd
6085
6108
 
6086
- def redraw_corner(self, x: float, y: float) -> None:
6109
+ def redraw_corner(self, x: float, y: float, tags: str | tuple[str]) -> None:
6087
6110
  if self.hidd_corners:
6088
6111
  iid = self.hidd_corners.pop()
6089
6112
  self.coords(iid, x - 10, y, x, y, x, y + 10)
6090
- self.itemconfig(iid, fill=self.PAR.ops.table_grid_fg, state="normal")
6113
+ self.itemconfig(iid, fill=self.PAR.ops.table_grid_fg, state="normal", tags=tags)
6091
6114
  self.disp_corners.add(iid)
6092
6115
  else:
6093
6116
  self.disp_corners.add(
6094
- self.create_polygon(x - 10, y, x, y, x, y + 10, fill=self.PAR.ops.table_grid_fg, tags="lift")
6117
+ self.create_polygon(x - 10, y, x, y, x, y + 10, fill=self.PAR.ops.table_grid_fg, tags=tags)
6095
6118
  )
6096
6119
 
6097
6120
  def redraw_grid_and_text(
@@ -6210,15 +6233,14 @@ class MainTable(tk.Canvas):
6210
6233
  rtopgridln = self.row_positions[r]
6211
6234
  rbotgridln = self.row_positions[r + 1]
6212
6235
  datarn = cells["datarn"][r]
6213
-
6214
6236
  for c in range(text_start_col, text_end_col):
6215
6237
  cleftgridln = self.col_positions[c]
6216
6238
  crightgridln = self.col_positions[c + 1]
6217
6239
  datacn = cells["datacn"][c]
6218
6240
  disp_loc = (r, c)
6219
6241
  loc = (datarn, datacn)
6220
-
6221
- fill, dd_drawn = self.redraw_highlight_get_text_fg(
6242
+ tag = f"{r}_{c}"
6243
+ fill, _ = self.redraw_highlight_get_text_fg(
6222
6244
  r=r,
6223
6245
  c=c,
6224
6246
  fc=cleftgridln,
@@ -6235,6 +6257,7 @@ class MainTable(tk.Canvas):
6235
6257
  dont_blend=disp_loc == dont_blend,
6236
6258
  alternate_color=alternate_color,
6237
6259
  has_dd=loc in cells["dropdown"],
6260
+ tags=("h", "c", tag),
6238
6261
  )
6239
6262
  if loc in self.cell_options and "align" in self.cell_options[(datarn, datacn)]:
6240
6263
  align = self.cell_options[(datarn, datacn)]["align"]
@@ -6261,8 +6284,8 @@ class MainTable(tk.Canvas):
6261
6284
  y1 = rtopgridln
6262
6285
  x2 = crightgridln
6263
6286
  y2 = self.row_positions[r + 1]
6264
- if not dd_drawn and self.PAR.ops.show_dropdown_borders:
6265
- self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.PAR.ops.table_fg)
6287
+ # if not dd_drawn and self.PAR.ops.show_dropdown_borders:
6288
+ # self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.PAR.ops.table_fg)
6266
6289
  if max_width >= 5:
6267
6290
  if dd_coords == disp_loc:
6268
6291
  # up arrow
@@ -6362,6 +6385,8 @@ class MainTable(tk.Canvas):
6362
6385
  elif align[-1] == "n":
6363
6386
  draw_x = cleftgridln + (crightgridln - cleftgridln) / 2
6364
6387
 
6388
+ tags = ("lift", "c", tag)
6389
+
6365
6390
  if (
6366
6391
  note_corners
6367
6392
  and max_width > 5
@@ -6371,12 +6396,14 @@ class MainTable(tk.Canvas):
6371
6396
  or (datacn in self.col_options and "note" in self.col_options[datacn])
6372
6397
  )
6373
6398
  ):
6374
- self.redraw_corner(crightgridln, rtopgridln)
6399
+ self.redraw_corner(crightgridln, rtopgridln, tags)
6375
6400
 
6376
6401
  # redraw text
6377
-
6378
- text = cells[loc]
6379
- if (align[-1] == "w" and draw_x > scrollpos_right) or cleftgridln + 5 > scrollpos_right:
6402
+ if (
6403
+ not cells[loc]
6404
+ or (align[-1] == "w" and draw_x > scrollpos_right)
6405
+ or cleftgridln + 5 > scrollpos_right
6406
+ ):
6380
6407
  continue
6381
6408
  if allow_overflow and not kws:
6382
6409
  if align[-1] == "w":
@@ -6388,7 +6415,7 @@ class MainTable(tk.Canvas):
6388
6415
  start_line = max(0, int((scrollpos_top - rtopgridln) / self.table_txt_height))
6389
6416
  draw_y = rtopgridln + 3 + (start_line * self.table_txt_height)
6390
6417
  gen_lines = wrap_text(
6391
- text=text,
6418
+ text=cells[loc],
6392
6419
  max_width=max_width,
6393
6420
  max_lines=int((rbotgridln - rtopgridln - 2) / self.table_txt_height),
6394
6421
  char_width_fn=self.wrap_get_char_w,
@@ -6407,7 +6434,7 @@ class MainTable(tk.Canvas):
6407
6434
  fill=fill,
6408
6435
  font=font,
6409
6436
  anchor=align,
6410
- tags=("lift", "t", f"{r}_{c}"),
6437
+ tags=tags,
6411
6438
  )
6412
6439
  else:
6413
6440
  self.itemconfig(
@@ -6417,7 +6444,7 @@ class MainTable(tk.Canvas):
6417
6444
  font=font,
6418
6445
  anchor=align,
6419
6446
  state="normal",
6420
- tags=("lift", "t", f"{r}_{c}"),
6447
+ tags=tags,
6421
6448
  )
6422
6449
  else:
6423
6450
  iid = self.create_text(
@@ -6427,7 +6454,7 @@ class MainTable(tk.Canvas):
6427
6454
  fill=fill,
6428
6455
  font=font,
6429
6456
  anchor=align,
6430
- tags=("lift", "t", f"{r}_{c}"),
6457
+ tags=tags,
6431
6458
  )
6432
6459
  self.disp_text[iid] = True
6433
6460
 
@@ -6443,7 +6470,7 @@ class MainTable(tk.Canvas):
6443
6470
  fill=fill,
6444
6471
  font=font,
6445
6472
  anchor=align,
6446
- tags=("lift", "t", f"{r}_{c}"),
6473
+ tags=tags,
6447
6474
  )
6448
6475
  else:
6449
6476
  self.itemconfig(
@@ -6453,7 +6480,7 @@ class MainTable(tk.Canvas):
6453
6480
  font=font,
6454
6481
  anchor=align,
6455
6482
  state="normal",
6456
- tags=("lift", "t", f"{r}_{c}"),
6483
+ tags=tags,
6457
6484
  )
6458
6485
  else:
6459
6486
  iid = self.create_text(
@@ -6463,7 +6490,7 @@ class MainTable(tk.Canvas):
6463
6490
  fill=fill,
6464
6491
  font=font,
6465
6492
  anchor=align,
6466
- tags=("lift", "t", f"{r}_{c}"),
6493
+ tags=tags,
6467
6494
  )
6468
6495
  self.disp_text[iid] = True
6469
6496
  draw_y += self.table_txt_height
@@ -6487,10 +6514,12 @@ class MainTable(tk.Canvas):
6487
6514
  if self.selected:
6488
6515
  self.tag_raise(self.selected.iid)
6489
6516
  self.lift("lift")
6490
- self.tag_bind("t", "<Enter>", self.enter_text)
6491
- self.tag_bind("t", "<Leave>", self.leave_text)
6517
+ self.tag_bind("c", "<Enter>", self.enter_cell)
6518
+ self.tag_bind("c", "<Leave>", self.leave_cell)
6492
6519
 
6493
- def enter_text(self, event: tk.Event | None = None) -> None:
6520
+ def enter_cell(self, event: tk.Event | None = None) -> None:
6521
+ if any_editor_or_dropdown_open(self):
6522
+ return
6494
6523
  can_x, can_y = self.canvasx(event.x), self.canvasy(event.y)
6495
6524
  for i in self.find_overlapping(can_x - 1, can_y - 1, can_x + 1, can_y + 1):
6496
6525
  try:
@@ -6503,7 +6532,7 @@ class MainTable(tk.Canvas):
6503
6532
  except Exception:
6504
6533
  continue
6505
6534
 
6506
- def leave_text(self, event: tk.Event | None = None) -> None:
6535
+ def leave_cell(self, event: tk.Event | None = None) -> None:
6507
6536
  if self.tooltip_after_id is not None:
6508
6537
  self.after_cancel(self.tooltip_after_id)
6509
6538
  self.tooltip_after_id = None
@@ -6514,7 +6543,7 @@ class MainTable(tk.Canvas):
6514
6543
  self.tooltip_coords = None
6515
6544
 
6516
6545
  def start_tooltip_timer(self) -> None:
6517
- self.tooltip_after_id = self.after(1000, self.check_and_show_tooltip)
6546
+ self.tooltip_after_id = self.after(self.PAR.ops.tooltip_hover_delay, self.check_and_show_tooltip)
6518
6547
 
6519
6548
  def check_and_show_tooltip(self, event: tk.Event | None = None) -> None:
6520
6549
  current_x, current_y = self.winfo_pointerx(), self.winfo_pointery()
@@ -6539,20 +6568,23 @@ class MainTable(tk.Canvas):
6539
6568
  kws = self.get_cell_kwargs(datarn, datacn, key="note")
6540
6569
  if not self.PAR.ops.tooltips and not kws and not self.PAR.ops.user_can_create_notes:
6541
6570
  return
6571
+ self.CH.hide_tooltip()
6572
+ self.RI.hide_tooltip()
6542
6573
  cell_readonly = self.get_cell_kwargs(datarn, datacn, "readonly") or not self.table_edit_cell_enabled()
6543
6574
  if kws:
6544
6575
  note = kws["note"]
6545
6576
  note_readonly = kws["readonly"]
6546
6577
  elif self.PAR.ops.user_can_create_notes:
6547
6578
  note = ""
6548
- note_readonly = bool(cell_readonly)
6579
+ note_readonly = False
6549
6580
  else:
6550
6581
  note = None
6551
6582
  note_readonly = True
6552
6583
  note_only = not self.PAR.ops.tooltips and isinstance(note, str)
6584
+ self.tooltip_cell_content = f"{self.get_cell_data(datarn, datacn, none_to_empty_str=True)}"
6553
6585
  self.tooltip.reset(
6554
6586
  **{
6555
- "text": f"{self.get_cell_data(datarn, datacn, none_to_empty_str=True)}",
6587
+ "text": self.tooltip_cell_content,
6556
6588
  "cell_readonly": cell_readonly,
6557
6589
  "note": note,
6558
6590
  "note_readonly": note_readonly,
@@ -6572,30 +6604,22 @@ class MainTable(tk.Canvas):
6572
6604
  def close_tooltip_save(self, event: tk.Event | None = None) -> None:
6573
6605
  widget = self.winfo_containing(self.winfo_pointerx(), self.winfo_pointery())
6574
6606
  if any(widget == tw for tw in self.tooltip_widgets):
6575
- try:
6576
- if self.tooltip.notebook.index("current") == 0:
6577
- self.tooltip.content_text.focus_set()
6578
- else:
6579
- self.tooltip.note_text.focus_set()
6580
- except Exception:
6581
- self.tooltip.content_text.focus_set()
6582
6607
  return
6583
6608
  if not self.tooltip.cell_readonly or not self.tooltip.note_readonly:
6584
6609
  r, c, cell, note = self.tooltip.get()
6585
6610
  datarn, datacn = self.datarn(r), self.datacn(c)
6586
- if not self.tooltip.cell_readonly:
6611
+ if not self.tooltip.cell_readonly and cell != self.tooltip_cell_content:
6587
6612
  event_data = self.new_single_edit_event(
6588
6613
  r, c, datarn, datacn, "??", self.get_cell_data(datarn, datacn), cell
6589
6614
  )
6590
6615
  value, event_data = self.single_edit_run_validation(datarn, datacn, event_data)
6591
- if value is not None and (
6616
+ if value is not None:
6592
6617
  self.set_cell_data_undo(r=r, c=c, datarn=datarn, datacn=datacn, value=value, redraw=False)
6593
- ):
6594
6618
  try_binding(self.extra_end_edit_cell_func, event_data)
6595
6619
  if not self.tooltip.note_readonly:
6596
6620
  self.PAR.note(datarn, datacn, note=note if note else None, readonly=False)
6621
+ self.refresh()
6597
6622
  self.hide_tooltip()
6598
- self.refresh()
6599
6623
  self.focus_set()
6600
6624
 
6601
6625
  def main_table_redraw_grid_and_text(
@@ -7344,6 +7368,7 @@ class MainTable(tk.Canvas):
7344
7368
  self.text_editor.window.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
7345
7369
  return False
7346
7370
  self.hide_text_editor()
7371
+ self.hide_tooltip()
7347
7372
  if not self.see(r, c):
7348
7373
  self.main_table_redraw_grid_and_text(True, True)
7349
7374
  x = self.col_positions[c]
tksheet/row_index.py CHANGED
@@ -20,6 +20,7 @@ from .constants import (
20
20
  from .formatters import is_bool_like, try_to_bool
21
21
  from .functions import (
22
22
  add_to_displayed,
23
+ any_editor_or_dropdown_open,
23
24
  consecutive_ranges,
24
25
  event_dict,
25
26
  event_has_char_key,
@@ -52,7 +53,7 @@ from .tooltip import Tooltip
52
53
 
53
54
 
54
55
  class RowIndex(tk.Canvas):
55
- def __init__(self, parent, **kwargs):
56
+ def __init__(self, parent: tk.Misc, **kwargs) -> None:
56
57
  super().__init__(
57
58
  parent,
58
59
  background=parent.ops.index_bg,
@@ -74,6 +75,7 @@ class RowIndex(tk.Canvas):
74
75
  )
75
76
  self.tooltip_widgets = widget_descendants(self.tooltip)
76
77
  self.tooltip_coords, self.tooltip_after_id, self.tooltip_showing = None, None, False
78
+ self.tooltip_cell_content = ""
77
79
  recursive_bind(self.tooltip, "<Leave>", self.close_tooltip_save)
78
80
  self.current_cursor = ""
79
81
  self.new_iid_ctr = -1
@@ -1311,6 +1313,7 @@ class RowIndex(tk.Canvas):
1311
1313
  selections: dict,
1312
1314
  datarn: int,
1313
1315
  has_dd: bool,
1316
+ tags: str | tuple[str],
1314
1317
  ) -> tuple[str, str, bool]:
1315
1318
  redrawn = False
1316
1319
  kwargs = self.get_cell_kwargs(datarn, key="highlight")
@@ -1337,6 +1340,7 @@ class RowIndex(tk.Canvas):
1337
1340
  + f"{int((int(high_bg[5:], 16) + int(sel_rows_bg[5:], 16)) / 2):02X}"
1338
1341
  ),
1339
1342
  outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
1343
+ tags=tags,
1340
1344
  )
1341
1345
  elif "cells" in selections and r in selections["cells"]:
1342
1346
  txtfg = (
@@ -1357,6 +1361,7 @@ class RowIndex(tk.Canvas):
1357
1361
  + f"{int((int(high_bg[5:], 16) + int(sel_cells_bg[5:], 16)) / 2):02X}"
1358
1362
  ),
1359
1363
  outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
1364
+ tags=tags,
1360
1365
  )
1361
1366
  else:
1362
1367
  txtfg = self.ops.index_fg if kwargs[1] is None else kwargs[1]
@@ -1368,6 +1373,7 @@ class RowIndex(tk.Canvas):
1368
1373
  sr,
1369
1374
  fill=high_bg,
1370
1375
  outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
1376
+ tags=tags,
1371
1377
  )
1372
1378
  tree_arrow_fg = txtfg
1373
1379
  elif not kwargs:
@@ -1381,6 +1387,7 @@ class RowIndex(tk.Canvas):
1381
1387
  sr,
1382
1388
  fill=self.ops.index_selected_rows_bg,
1383
1389
  outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
1390
+ tags=tags,
1384
1391
  )
1385
1392
  elif "cells" in selections and r in selections["cells"]:
1386
1393
  txtfg = self.ops.index_selected_cells_fg
@@ -1392,10 +1399,20 @@ class RowIndex(tk.Canvas):
1392
1399
  sr,
1393
1400
  fill=self.ops.index_selected_cells_bg,
1394
1401
  outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
1402
+ tags=tags,
1395
1403
  )
1396
1404
  else:
1397
1405
  txtfg = self.ops.index_fg
1398
1406
  tree_arrow_fg = self.ops.tree_arrow_fg
1407
+ redrawn = self.redraw_highlight(
1408
+ 0,
1409
+ fr + 1,
1410
+ self.current_width - 1,
1411
+ sr,
1412
+ fill="",
1413
+ outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
1414
+ tags=tags,
1415
+ )
1399
1416
  return txtfg, tree_arrow_fg, redrawn
1400
1417
 
1401
1418
  def redraw_highlight(
@@ -1406,17 +1423,18 @@ class RowIndex(tk.Canvas):
1406
1423
  y2: float,
1407
1424
  fill: str,
1408
1425
  outline: str,
1426
+ tags: str | tuple[str],
1409
1427
  ) -> bool:
1410
1428
  coords = (x1, y1, x2, y2)
1411
1429
  if self.hidd_high:
1412
1430
  iid, showing = self.hidd_high.popitem()
1413
1431
  self.coords(iid, coords)
1414
1432
  if showing:
1415
- self.itemconfig(iid, fill=fill, outline=outline)
1433
+ self.itemconfig(iid, fill=fill, outline=outline, tags=tags)
1416
1434
  else:
1417
- self.itemconfig(iid, fill=fill, outline=outline, state="normal")
1435
+ self.itemconfig(iid, fill=fill, outline=outline, state="normal", tags=tags)
1418
1436
  else:
1419
- iid = self.create_rectangle(coords, fill=fill, outline=outline)
1437
+ iid = self.create_rectangle(coords, fill=fill, outline=outline, tags=tags)
1420
1438
  self.disp_high[iid] = True
1421
1439
  return True
1422
1440
 
@@ -1539,8 +1557,8 @@ class RowIndex(tk.Canvas):
1539
1557
  draw_arrow: bool = True,
1540
1558
  open_: bool = False,
1541
1559
  ) -> None:
1542
- if draw_outline and self.ops.show_dropdown_borders:
1543
- self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.ops.index_fg)
1560
+ # if draw_outline and self.ops.show_dropdown_borders:
1561
+ # self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.ops.index_fg)
1544
1562
  if draw_arrow:
1545
1563
  mod = (self.MT.index_txt_height - 1) if self.MT.index_txt_height % 2 else self.MT.index_txt_height
1546
1564
  small_mod = int(mod / 5)
@@ -1650,15 +1668,15 @@ class RowIndex(tk.Canvas):
1650
1668
  self.MT.char_widths[self.index_font][c] = wd
1651
1669
  return wd
1652
1670
 
1653
- def redraw_corner(self, x: float, y: float) -> None:
1671
+ def redraw_corner(self, x: float, y: float, tags: str | tuple[str]) -> None:
1654
1672
  if self.hidd_corners:
1655
1673
  iid = self.hidd_corners.pop()
1656
1674
  self.coords(iid, x - 10, y, x, y, x, y + 10)
1657
- self.itemconfig(iid, fill=self.ops.index_grid_fg, state="normal")
1675
+ self.itemconfig(iid, fill=self.ops.index_grid_fg, state="normal", tags=tags)
1658
1676
  self.disp_corners.add(iid)
1659
1677
  else:
1660
1678
  self.disp_corners.add(
1661
- self.create_polygon(x - 10, y, x, y, x, y + 10, fill=self.ops.index_grid_fg, tags="lift")
1679
+ self.create_polygon(x - 10, y, x, y, x, y + 10, fill=self.ops.index_grid_fg, tags=tags)
1662
1680
  )
1663
1681
 
1664
1682
  def redraw_grid_and_text(
@@ -1697,7 +1715,6 @@ class RowIndex(tk.Canvas):
1697
1715
  self.current_width,
1698
1716
  scrollpos_bot,
1699
1717
  )
1700
-
1701
1718
  if (self.ops.show_horizontal_grid or self.height_resizing_enabled) and row_pos_exists:
1702
1719
  xend = self.current_width - 6
1703
1720
  points = [
@@ -1725,7 +1742,6 @@ class RowIndex(tk.Canvas):
1725
1742
  )
1726
1743
  )
1727
1744
  self.redraw_gridline(points=points, fill=self.ops.index_grid_fg, width=1)
1728
-
1729
1745
  sel_cells_bg = (
1730
1746
  self.ops.index_selected_cells_bg
1731
1747
  if self.ops.index_selected_cells_bg.startswith("#")
@@ -1750,6 +1766,7 @@ class RowIndex(tk.Canvas):
1750
1766
  checkbox_kwargs = {}
1751
1767
  datarn = r if self.MT.all_rows_displayed else self.MT.displayed_rows[r]
1752
1768
  dropdown_kwargs = self.get_cell_kwargs(datarn, key="dropdown")
1769
+ tag = f"{r}"
1753
1770
  fill, tree_arrow_fg, dd_drawn = self.redraw_highlight_get_text_fg(
1754
1771
  fr=rtopgridln,
1755
1772
  sr=rbotgridln,
@@ -1759,8 +1776,8 @@ class RowIndex(tk.Canvas):
1759
1776
  selections=selections,
1760
1777
  datarn=datarn,
1761
1778
  has_dd=bool(dropdown_kwargs),
1779
+ tags=("h", "c", tag),
1762
1780
  )
1763
-
1764
1781
  if datarn in self.cell_options and "align" in self.cell_options[datarn]:
1765
1782
  align = self.cell_options[datarn]["align"]
1766
1783
  else:
@@ -1837,10 +1854,9 @@ class RowIndex(tk.Canvas):
1837
1854
  open_=self.MT._row_index[datarn].iid in self.tree_open_ids,
1838
1855
  level=level,
1839
1856
  )
1840
-
1857
+ tags = ("lift", "c", tag)
1841
1858
  if note_corners and max_width > 5 and datarn in self.cell_options and "note" in self.cell_options[datarn]:
1842
- self.redraw_corner(self.current_width, rtopgridln)
1843
-
1859
+ self.redraw_corner(self.current_width, rtopgridln, tags)
1844
1860
  if max_width <= 1:
1845
1861
  continue
1846
1862
  text = self.cell_str(datarn, fix=False)
@@ -1868,7 +1884,7 @@ class RowIndex(tk.Canvas):
1868
1884
  fill=fill,
1869
1885
  font=font,
1870
1886
  anchor=align,
1871
- tags=("lift", "t", f"{r}"),
1887
+ tags=tags,
1872
1888
  )
1873
1889
  else:
1874
1890
  self.itemconfig(
@@ -1878,7 +1894,7 @@ class RowIndex(tk.Canvas):
1878
1894
  font=font,
1879
1895
  anchor=align,
1880
1896
  state="normal",
1881
- tags=("lift", "t", f"{r}"),
1897
+ tags=tags,
1882
1898
  )
1883
1899
  else:
1884
1900
  iid = self.create_text(
@@ -1888,7 +1904,7 @@ class RowIndex(tk.Canvas):
1888
1904
  fill=fill,
1889
1905
  font=font,
1890
1906
  anchor=align,
1891
- tags=("lift", "t", f"{r}"),
1907
+ tags=tags,
1892
1908
  )
1893
1909
  self.disp_text[iid] = True
1894
1910
  else:
@@ -1903,7 +1919,7 @@ class RowIndex(tk.Canvas):
1903
1919
  fill=fill,
1904
1920
  font=font,
1905
1921
  anchor=align,
1906
- tags=("lift", "t", f"{r}"),
1922
+ tags=tags,
1907
1923
  )
1908
1924
  else:
1909
1925
  self.itemconfig(
@@ -1913,7 +1929,7 @@ class RowIndex(tk.Canvas):
1913
1929
  font=font,
1914
1930
  anchor=align,
1915
1931
  state="normal",
1916
- tags=("lift", "t", f"{r}"),
1932
+ tags=tags,
1917
1933
  )
1918
1934
  else:
1919
1935
  iid = self.create_text(
@@ -1923,7 +1939,7 @@ class RowIndex(tk.Canvas):
1923
1939
  fill=fill,
1924
1940
  font=font,
1925
1941
  anchor=align,
1926
- tags=("lift", "t", f"{r}"),
1942
+ tags=tags,
1927
1943
  )
1928
1944
  self.disp_text[iid] = True
1929
1945
  draw_y += self.MT.header_txt_height
@@ -1945,12 +1961,12 @@ class RowIndex(tk.Canvas):
1945
1961
  self.tag_raise("lift")
1946
1962
  if self.disp_resize_lines:
1947
1963
  self.tag_raise("rh")
1948
- self.tag_bind("t", "<Enter>", self.enter_text)
1949
- self.tag_bind("t", "<Leave>", self.leave_text)
1964
+ self.tag_bind("c", "<Enter>", self.enter_cell)
1965
+ self.tag_bind("c", "<Leave>", self.leave_cell)
1950
1966
  return True
1951
1967
 
1952
- def enter_text(self, event: tk.Event | None = None) -> None:
1953
- if self.text_editor.open or self.dropdown.open:
1968
+ def enter_cell(self, event: tk.Event | None = None) -> None:
1969
+ if any_editor_or_dropdown_open(self.MT):
1954
1970
  return
1955
1971
  can_x, can_y = self.canvasx(event.x), self.canvasy(event.y)
1956
1972
  for i in self.find_overlapping(can_x - 1, can_y - 1, can_x + 1, can_y + 1):
@@ -1964,7 +1980,7 @@ class RowIndex(tk.Canvas):
1964
1980
  except Exception:
1965
1981
  continue
1966
1982
 
1967
- def leave_text(self, event: tk.Event | None = None) -> None:
1983
+ def leave_cell(self, event: tk.Event | None = None) -> None:
1968
1984
  if self.tooltip_after_id is not None:
1969
1985
  self.after_cancel(self.tooltip_after_id)
1970
1986
  self.tooltip_after_id = None
@@ -1975,7 +1991,7 @@ class RowIndex(tk.Canvas):
1975
1991
  self.tooltip_coords = None
1976
1992
 
1977
1993
  def start_tooltip_timer(self) -> None:
1978
- self.tooltip_after_id = self.after(1000, self.check_and_show_tooltip)
1994
+ self.tooltip_after_id = self.after(self.ops.tooltip_hover_delay, self.check_and_show_tooltip)
1979
1995
 
1980
1996
  def check_and_show_tooltip(self, event: tk.Event | None = None) -> None:
1981
1997
  current_x, current_y = self.winfo_pointerx(), self.winfo_pointery()
@@ -1997,19 +2013,22 @@ class RowIndex(tk.Canvas):
1997
2013
  kws = self.get_cell_kwargs(datarn, key="note")
1998
2014
  if not self.ops.tooltips and not kws and not self.ops.user_can_create_notes:
1999
2015
  return
2016
+ self.MT.hide_tooltip()
2017
+ self.CH.hide_tooltip()
2000
2018
  cell_readonly = self.get_cell_kwargs(datarn, "readonly") or not self.MT.index_edit_cell_enabled()
2001
2019
  if kws:
2002
2020
  note = kws["note"]
2003
2021
  note_readonly = kws["readonly"]
2004
2022
  elif self.ops.user_can_create_notes:
2005
2023
  note = ""
2006
- note_readonly = bool(cell_readonly)
2024
+ note_readonly = False
2007
2025
  else:
2008
2026
  note = None
2009
2027
  note_readonly = True
2028
+ self.tooltip_cell_content = f"{self.get_cell_data(datarn, none_to_empty_str=True)}"
2010
2029
  self.tooltip.reset(
2011
2030
  **{
2012
- "text": f"{self.get_cell_data(datarn, none_to_empty_str=True)}",
2031
+ "text": self.tooltip_cell_content,
2013
2032
  "cell_readonly": cell_readonly,
2014
2033
  "note": note,
2015
2034
  "note_readonly": note_readonly,
@@ -2029,25 +2048,18 @@ class RowIndex(tk.Canvas):
2029
2048
  def close_tooltip_save(self, event: tk.Event | None = None) -> None:
2030
2049
  widget = self.winfo_containing(self.winfo_pointerx(), self.winfo_pointery())
2031
2050
  if any(widget == tw for tw in self.tooltip_widgets):
2032
- try:
2033
- if self.tooltip.notebook.index("current") == 0:
2034
- self.tooltip.content_text.focus_set()
2035
- else:
2036
- self.tooltip.note_text.focus_set()
2037
- except Exception:
2038
- self.tooltip.content_text.focus_set()
2039
2051
  return
2040
2052
  if not self.tooltip.cell_readonly or not self.tooltip.note_readonly:
2041
2053
  r, _, cell, note = self.tooltip.get()
2042
2054
  datarn = self.MT.datarn(r)
2043
- if not self.tooltip.cell_readonly:
2055
+ if not self.tooltip.cell_readonly and cell != self.tooltip_cell_content:
2044
2056
  event_data = self.new_single_edit_event(r, datarn, "??", self.get_cell_data(datarn), cell)
2045
2057
  self.do_single_edit(r, datarn, event_data, cell)
2046
2058
  if not self.tooltip.note_readonly:
2047
2059
  span = self.PAR.span(datarn).options(table=False, index=True)
2048
2060
  self.PAR.note(span, note=note if note else None, readonly=False)
2061
+ self.MT.refresh()
2049
2062
  self.hide_tooltip()
2050
- self.MT.refresh()
2051
2063
  self.focus_set()
2052
2064
 
2053
2065
  def get_redraw_selections(self, startr: int, endr: int) -> dict[str, set[int]]:
@@ -2132,6 +2144,7 @@ class RowIndex(tk.Canvas):
2132
2144
  self.text_editor.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
2133
2145
  return False
2134
2146
  self.hide_text_editor()
2147
+ self.hide_tooltip()
2135
2148
  if not self.MT.see(r, 0, keep_yscroll=True):
2136
2149
  self.MT.main_table_redraw_grid_and_text(True, True)
2137
2150
  x = 0
tksheet/sheet.py CHANGED
@@ -206,6 +206,7 @@ class Sheet(tk.Frame):
206
206
  note_corners: bool = False,
207
207
  tooltip_width: int = 210,
208
208
  tooltip_height: int = 210,
209
+ tooltip_hover_delay: int = 1200,
209
210
  # colors
210
211
  outline_thickness: int = 0,
211
212
  theme: str = "light blue",
@@ -4669,51 +4670,52 @@ class Sheet(tk.Frame):
4669
4670
  deselect_all=False,
4670
4671
  data_indexes=True,
4671
4672
  )
4672
- open_ids = set(filter(self.exists, open_ids))
4673
4673
  self.RI.tree_open_ids = set()
4674
- if open_ids:
4675
- self.show_rows(
4676
- rows=self._tree_open(open_ids),
4677
- redraw=False,
4678
- deselect_all=False,
4679
- )
4674
+ open_ids = filter(self.exists, open_ids)
4675
+ try:
4676
+ first_id = next(open_ids)
4677
+ except StopIteration:
4678
+ return self.set_refresh_timer()
4679
+ self.show_rows(
4680
+ rows=self._tree_open(chain((first_id,), open_ids)),
4681
+ redraw=False,
4682
+ deselect_all=False,
4683
+ )
4680
4684
  return self.set_refresh_timer()
4681
4685
 
4682
- def _tree_open(self, items: set[str]) -> list[int]:
4686
+ def _tree_open(self, items: Iterator[str]) -> Generator[int]:
4683
4687
  """
4684
4688
  Only meant for internal use
4685
4689
  """
4686
- to_open = []
4687
4690
  disp_set = set(self.MT.displayed_rows)
4688
4691
  index = self.MT._row_index
4689
4692
  rns = self.RI.rns
4690
4693
  open_ids = self.RI.tree_open_ids
4691
4694
  descendants = self.RI.get_iid_descendants
4692
- for item in filter(items.__contains__, self.get_children()):
4693
- if index[rns[item]].children:
4695
+ for item in items:
4696
+ if item in rns and index[rns[item]].children:
4694
4697
  open_ids.add(item)
4695
4698
  if rns[item] in disp_set:
4696
4699
  for did in descendants(item, check_open=True):
4697
4700
  disp_set.add(rns[did])
4698
- to_open.append(rns[did])
4699
- return to_open
4701
+ yield rns[did]
4700
4702
 
4701
- def tree_open(self, *items, redraw: bool = True) -> Sheet:
4703
+ def tree_open(self, *items: str, redraw: bool = True) -> Sheet:
4702
4704
  """
4703
4705
  If used without args all items are opened
4704
4706
  """
4705
- to_open = self._tree_open(items) if (items := set(unpack(items))) else self._tree_open(set(self.get_children()))
4707
+ to_show = self._tree_open(items) if (items := set(unpack(items))) else self._tree_open(self.get_children())
4706
4708
  return self.show_rows(
4707
- rows=to_open,
4709
+ rows=to_show,
4708
4710
  redraw=redraw,
4709
4711
  deselect_all=False,
4710
4712
  )
4711
4713
 
4712
- def _tree_close(self, items: Iterator[str]) -> list[int]:
4714
+ def _tree_close(self, items: Iterator[str]) -> set[int]:
4713
4715
  """
4714
4716
  Only meant for internal use
4715
4717
  """
4716
- to_close = set()
4718
+ to_hide = set()
4717
4719
  disp_set = set(self.MT.displayed_rows)
4718
4720
  index = self.MT._row_index
4719
4721
  rns = self.RI.rns
@@ -4724,16 +4726,16 @@ class Sheet(tk.Frame):
4724
4726
  open_ids.discard(item)
4725
4727
  if rns[item] in disp_set:
4726
4728
  for did in descendants(item, check_open=True):
4727
- to_close.add(rns[did])
4728
- return to_close
4729
+ to_hide.add(rns[did])
4730
+ return to_hide
4729
4731
 
4730
- def tree_close(self, *items, redraw: bool = True) -> Sheet:
4732
+ def tree_close(self, *items: str, redraw: bool = True) -> Sheet:
4731
4733
  """
4732
4734
  If used without args all items are closed
4733
4735
  """
4734
- to_close = self._tree_close(unpack(items)) if items else self._tree_close(self.get_children())
4736
+ to_hide = self._tree_close(unpack(items)) if items else self._tree_close(self.get_children())
4735
4737
  return self.hide_rows(
4736
- rows=to_close,
4738
+ rows=to_hide,
4737
4739
  redraw=redraw,
4738
4740
  deselect_all=False,
4739
4741
  data_indexes=True,
@@ -5109,7 +5111,7 @@ class Sheet(tk.Frame):
5109
5111
  """
5110
5112
  if not self.item_displayed(item) and self.RI.iid_parent(item):
5111
5113
  self.show_rows(
5112
- rows=self._tree_open(list(self.RI.get_iid_ancestors(item))),
5114
+ rows=self._tree_open(self.RI.get_iid_ancestors(item)),
5113
5115
  redraw=False,
5114
5116
  deselect_all=False,
5115
5117
  )
@@ -5154,11 +5156,11 @@ class Sheet(tk.Frame):
5154
5156
  return self.set_refresh_timer(redraw)
5155
5157
 
5156
5158
  def selection_add(self, *items, run_binding: bool = True, redraw: bool = True) -> Sheet:
5157
- to_open = []
5159
+ to_open = set()
5158
5160
  quick_displayed_check = set(self.MT.displayed_rows)
5159
5161
  for item in filter(self.RI.rns.__contains__, unpack(items)):
5160
5162
  if self.RI.rns[item] not in quick_displayed_check and self.RI.iid_parent(item):
5161
- to_open.extend(list(self.RI.get_iid_ancestors(item)))
5163
+ to_open.update(self.RI.get_iid_ancestors(item))
5162
5164
  if to_open:
5163
5165
  self.show_rows(
5164
5166
  rows=self._tree_open(to_open),
tksheet/sheet_options.py CHANGED
@@ -370,5 +370,6 @@ def new_sheet_options() -> DotDict:
370
370
  "note_corners": False,
371
371
  "tooltip_width": 210,
372
372
  "tooltip_height": 210,
373
+ "tooltip_hover_delay": 1200,
373
374
  }
374
375
  )
tksheet/tooltip.py CHANGED
@@ -217,7 +217,7 @@ class Tooltip(tk.Toplevel):
217
217
  self.note_scrollbar.configure(command=self.note_text.yview)
218
218
  self.note_text.configure(yscrollcommand=self.note_scrollbar.set)
219
219
 
220
- def setup_note_only_mode(self):
220
+ def setup_note_only_mode(self) -> None:
221
221
  """Configure the tooltip to show only the note text widget."""
222
222
  self.notebook.pack_forget() # Remove notebook from layout
223
223
  for tab in self.notebook.tabs(): # Clear all tabs to free the frames
@@ -225,7 +225,7 @@ class Tooltip(tk.Toplevel):
225
225
  self.content_frame.pack_forget() # Ensure content_frame is not directly packed
226
226
  self.note_frame.pack(fill="both", expand=True) # Show note_frame directly
227
227
 
228
- def setup_single_text_mode(self):
228
+ def setup_single_text_mode(self) -> None:
229
229
  """Configure the tooltip to show only the content text widget."""
230
230
  self.notebook.pack_forget() # Remove notebook from layout
231
231
  for tab in self.notebook.tabs(): # Clear all tabs
@@ -233,7 +233,7 @@ class Tooltip(tk.Toplevel):
233
233
  self.note_frame.pack_forget() # Ensure note_frame is not directly packed
234
234
  self.content_frame.pack(fill="both", expand=True) # Show content_frame directly
235
235
 
236
- def setup_notebook_mode(self):
236
+ def setup_notebook_mode(self) -> None:
237
237
  """Configure the tooltip to show a notebook with Cell and Note tabs."""
238
238
  self.content_frame.pack_forget() # Ensure content_frame is not directly packed
239
239
  self.note_frame.pack_forget() # Ensure note_frame is not directly packed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tksheet
3
- Version: 7.5.10
3
+ Version: 7.5.12
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
@@ -77,6 +77,8 @@ Dynamic: license-file
77
77
 
78
78
  [![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/)
79
79
 
80
+ With apologies, development of this library has ceased except for bug fixes or behavioral issues. Pull requests for other changes are unlikely to be merged.
81
+
80
82
  <table>
81
83
  <thead>
82
84
  <tr>
@@ -95,14 +97,11 @@ Dynamic: license-file
95
97
  <tr>
96
98
  <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/blob/master/docs/CHANGELOG.md" target="_blank">Changelog</a></td>
97
99
  </tr>
98
- <tr>
99
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#asking-questions" target="_blank">Questions</a></td>
100
- </tr>
101
100
  <tr>
102
101
  <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#issues" target="_blank">Issues</a></td>
103
102
  </tr>
104
103
  <tr>
105
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#enhancements-or-suggestions" target="_blank">Suggestions and Contributors</a></td>
104
+ <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#contributions-and-special-thanks" target="_blank">Contributions and Thanks</a></td>
106
105
  </tr>
107
106
  </tbody>
108
107
  </table>
@@ -1,24 +1,24 @@
1
- tksheet/__init__.py,sha256=3Ue-5hmalzD8JxLLXk1WoBPBWdZ3MWkFfs_3wx0S2w8,2533
1
+ tksheet/__init__.py,sha256=fD70jpRTugB9VWfpt6BManIsp4vrlXl9UK5RU74jmYc,2533
2
2
  tksheet/colors.py,sha256=dHhmdFuQDlwohDHsAfT9VdrKoSl_R33L72a3HCin5zo,51591
3
- tksheet/column_headers.py,sha256=-i8LMCUW1UuKpyurWySJRyjiCqisgFrjm9l8U58bFAY,110720
3
+ tksheet/column_headers.py,sha256=CkJBfgLu3qcXDJWhYT8mWniH81kMDeWsqcCoRko_FHo,111362
4
4
  tksheet/constants.py,sha256=4cpU_PmOgN0isBVPWwCwBwqD8Fxnu4HJgDSSjfxjiPo,25467
5
5
  tksheet/find_window.py,sha256=aV2U-IDFL6xNRhF4VomdrXEML4qw6QBqlfrVskuiTNY,20954
6
6
  tksheet/formatters.py,sha256=r2vjgmKs_xWBYlfqVhPPNKQc67zCawOIl4dp4XAEzYg,10182
7
- tksheet/functions.py,sha256=O74jt9Kq-JgtWaI7fHBXbIbCTdi79B3eHidR-wfiAZ0,56585
8
- tksheet/main_table.py,sha256=awMX6ABc_LW-gzhZh9MKnyMv9-ZKpBEQUcEylwKjVMA,368162
7
+ tksheet/functions.py,sha256=l4iwL-0RT0NrQTP1AKb6QGzAF01Sk-I6Kp5TaWb8ARw,56795
8
+ tksheet/main_table.py,sha256=XeonBS6BeuVb057TAbvphcULWPTL0mkTqLMVWLeXPh4,369093
9
9
  tksheet/menus.py,sha256=sRHZRgnYWddBtlzvbyWFSN2cVhlmUWyA9zf4vpqun7I,19431
10
10
  tksheet/other_classes.py,sha256=6LpexHAxj23ZweuL3a4yCcdMSj_iXP38S7WRNQAehe0,18354
11
- tksheet/row_index.py,sha256=wmoQylsUJQMnbONIndeRM_gW9eHJg-DdmX6MjxqlQlk,146892
12
- tksheet/sheet.py,sha256=gYm2o_chSI9vCtxY4r5j9soKQXXWFgvuH2FrEd3IGc4,273109
13
- tksheet/sheet_options.py,sha256=dhHY4jUULGXH2b_VOjoAfKXm3PAz7QL5CrVnHA0byho,14697
11
+ tksheet/row_index.py,sha256=RG9Z59ssefTVFmOR_kuu5LiUlRcSz1vO6KhM1pIWUYo,147530
12
+ tksheet/sheet.py,sha256=l2wmgl2gHmL1G2RDPm-qRlwGShRHLQQMHzbdeoTzkfk,273171
13
+ tksheet/sheet_options.py,sha256=Lse8YQK9GvCoqaEcRWAVqZrg9FyW-2CKgLwo7t9ee_I,14739
14
14
  tksheet/sorting.py,sha256=zcZPpRtP1h_xJGtGkG3E43H7deKQFnh9cMwZ1B2-aGc,17502
15
15
  tksheet/text_editor.py,sha256=Ksz4kT7TrCIzDhRZK9EM54M7R_5CvrwC1aeTrUPNOTg,8391
16
16
  tksheet/themes.py,sha256=kUUCUmvgu8vUlzfVNk9a3BEbeBcU3asNwPB_u-OejCY,18471
17
17
  tksheet/tksheet_types.py,sha256=qthH565jq60QCAeczvIWttIa4X5rFfLWPSwWBMDPilw,4611
18
- tksheet/tooltip.py,sha256=TTWk3HW5Sltamish9GCnAECwZLa9Rm6QC8-RCDDtQnE,12374
18
+ tksheet/tooltip.py,sha256=Ns7MhhSzx0-5v18TDE7kl5jvOnZ6v57Qh5DOs_Lvc5s,12398
19
19
  tksheet/top_left_rectangle.py,sha256=A4wWL8PFl57Pn2Ek71rASCE1-bW844cTl7bgt4tLWzI,8499
20
- tksheet-7.5.10.dist-info/licenses/LICENSE.txt,sha256=n1UvJHBr-AYNOf6ExICDsEggh9R7U4V4m_gH7FD-y-o,2305
21
- tksheet-7.5.10.dist-info/METADATA,sha256=GI9d24XzxknLTYE8ITC4_dWUii4pG2r_P-jczO3Sb6I,9475
22
- tksheet-7.5.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- tksheet-7.5.10.dist-info/top_level.txt,sha256=my61PXCcck_HHAc9cq3NAlyAr3A3FXxCy9gptEOaCN8,8
24
- tksheet-7.5.10.dist-info/RECORD,,
20
+ tksheet-7.5.12.dist-info/licenses/LICENSE.txt,sha256=n1UvJHBr-AYNOf6ExICDsEggh9R7U4V4m_gH7FD-y-o,2305
21
+ tksheet-7.5.12.dist-info/METADATA,sha256=Ea9FCFWptle102ucKjdC8dIV2s2Ze-tQ-Lxaz-AAS5Y,9465
22
+ tksheet-7.5.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ tksheet-7.5.12.dist-info/top_level.txt,sha256=my61PXCcck_HHAc9cq3NAlyAr3A3FXxCy9gptEOaCN8,8
24
+ tksheet-7.5.12.dist-info/RECORD,,