tksheet 7.1.4__py3-none-any.whl → 7.1.6__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.1.4"
7
+ __version__ = "7.1.6"
8
8
 
9
9
  from .colors import (
10
10
  color_map,
tksheet/column_headers.py CHANGED
@@ -13,13 +13,14 @@ from itertools import (
13
13
  islice,
14
14
  )
15
15
  from math import ceil, floor
16
+ from typing import Literal
16
17
 
17
18
  from .colors import (
18
19
  color_map,
19
20
  )
20
21
  from .formatters import is_bool_like, try_to_bool
21
22
  from .functions import (
22
- consecutive_chunks,
23
+ consecutive_ranges,
23
24
  ev_stack_dict,
24
25
  event_dict,
25
26
  get_checkbox_points,
@@ -272,7 +273,9 @@ class ColumnHeaders(tk.Canvas):
272
273
  if self.MT.selected and self.MT.selected.type_ == "columns":
273
274
  r_to_sel, c_to_sel = self.MT.selected.row, self.MT.selected.column
274
275
  self.MT.deselect("all", redraw=False)
275
- self.being_drawn_item = self.MT.create_selection_box(*self.get_shift_select_box(c, c_to_sel), "columns")
276
+ self.being_drawn_item = self.MT.create_selection_box(
277
+ *self.get_shift_select_box(c, c_to_sel), "columns"
278
+ )
276
279
  self.MT.set_currently_selected(r_to_sel, c_to_sel, self.being_drawn_item)
277
280
  else:
278
281
  self.being_drawn_item = self.select_col(c, run_binding_func=False)
@@ -685,10 +688,10 @@ class ColumnHeaders(tk.Canvas):
685
688
  tag="move_columns",
686
689
  )
687
690
  self.MT.create_resize_line(xpos, y1, xpos, y2, width=3, fill=self.PAR.ops.drag_and_drop_bg, tag="move_columns")
688
- for chunk in consecutive_chunks(cols):
691
+ for boxst, boxend in consecutive_ranges(cols):
689
692
  self.MT.show_ctrl_outline(
690
- start_cell=(chunk[0], 0),
691
- end_cell=(chunk[-1] + 1, len(self.MT.row_positions) - 1),
693
+ start_cell=(boxst, 0),
694
+ end_cell=(boxend, len(self.MT.row_positions) - 1),
692
695
  dash=(),
693
696
  outline=self.PAR.ops.drag_and_drop_bg,
694
697
  delete_on_timer=False,
@@ -854,8 +857,16 @@ class ColumnHeaders(tk.Canvas):
854
857
  ):
855
858
  datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
856
859
  canvasx = self.canvasx(event.x)
857
- if self.event_over_dropdown(c, datacn, event, canvasx) or self.event_over_checkbox(
858
- c, datacn, event, canvasx
860
+ if self.event_over_dropdown(
861
+ c,
862
+ datacn,
863
+ event,
864
+ canvasx,
865
+ ) or self.event_over_checkbox(
866
+ c,
867
+ datacn,
868
+ event,
869
+ canvasx,
859
870
  ):
860
871
  self.open_cell(event)
861
872
  else:
@@ -970,15 +981,15 @@ class ColumnHeaders(tk.Canvas):
970
981
  qconf = self.MT.txt_measure_canvas.itemconfig
971
982
  qbbox = self.MT.txt_measure_canvas.bbox
972
983
  qtxtm = self.MT.txt_measure_canvas_text
984
+ qfont = self.PAR.ops.header_font
973
985
  new_height = self.MT.min_header_height
974
986
  default_header_height = self.MT.get_default_header_height()
975
987
  self.fix_header()
976
988
  if text is not None:
977
989
  if text:
978
- qconf(qtxtm, text=text)
990
+ qconf(qtxtm, text=text, font=qfont)
979
991
  b = qbbox(qtxtm)
980
- h = b[3] - b[1] + 5
981
- if h > new_height:
992
+ if (h := b[3] - b[1] + 5) > new_height:
982
993
  new_height = h
983
994
  else:
984
995
  if self.MT.all_columns_displayed:
@@ -1002,7 +1013,7 @@ class ColumnHeaders(tk.Canvas):
1002
1013
  for datacn in iterable:
1003
1014
  txt = self.MT.get_valid_cell_data_as_str(datarn, datacn, get_displayed=True)
1004
1015
  if txt:
1005
- qconf(qtxtm, text=txt)
1016
+ qconf(qtxtm, text=txt, font=qfont)
1006
1017
  b = qbbox(qtxtm)
1007
1018
  h = b[3] - b[1] + 5
1008
1019
  else:
@@ -1014,7 +1025,7 @@ class ColumnHeaders(tk.Canvas):
1014
1025
  if h > new_height:
1015
1026
  new_height = h
1016
1027
  space_bot = self.MT.get_space_bot(0)
1017
- if new_height > space_bot:
1028
+ if new_height > space_bot and space_bot > self.MT.min_header_height:
1018
1029
  new_height = space_bot
1019
1030
  if not only_increase or (only_increase and new_height > self.current_height):
1020
1031
  self.set_height(new_height, set_TL=True)
@@ -1612,14 +1623,13 @@ class ColumnHeaders(tk.Canvas):
1612
1623
  ) -> bool:
1613
1624
  text = None
1614
1625
  extra_func_key = "??"
1615
- datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
1616
1626
  if event is None or self.MT.event_opens_dropdown_or_checkbox(event):
1617
1627
  if event is not None:
1618
1628
  if hasattr(event, "keysym") and event.keysym == "Return":
1619
1629
  extra_func_key = "Return"
1620
1630
  elif hasattr(event, "keysym") and event.keysym == "F2":
1621
1631
  extra_func_key = "F2"
1622
- text = self.get_cell_data(datacn, none_to_empty_str=True, redirect_int=True)
1632
+ text = self.get_cell_data(self.MT.datacn(c), none_to_empty_str=True, redirect_int=True)
1623
1633
  elif event is not None and (
1624
1634
  (hasattr(event, "keysym") and event.keysym == "BackSpace") or event.keycode in (8, 855638143)
1625
1635
  ):
@@ -1669,9 +1679,8 @@ class ColumnHeaders(tk.Canvas):
1669
1679
  y = 0
1670
1680
  w = self.MT.col_positions[c + 1] - x
1671
1681
  h = self.current_height + 1
1672
- datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
1673
1682
  if text is None:
1674
- text = self.get_cell_data(datacn, none_to_empty_str=True, redirect_int=True)
1683
+ text = self.get_cell_data(self.MT.datacn(c), none_to_empty_str=True, redirect_int=True)
1675
1684
  bg, fg = self.PAR.ops.header_bg, self.PAR.ops.header_fg
1676
1685
  kwargs = {
1677
1686
  "menu_kwargs": DotDict(
@@ -1684,12 +1693,12 @@ class ColumnHeaders(tk.Canvas):
1684
1693
  }
1685
1694
  ),
1686
1695
  "sheet_ops": self.PAR.ops,
1687
- "border_color": self.PAR.ops.table_selected_cells_border_fg,
1696
+ "border_color": self.PAR.ops.header_selected_columns_bg,
1688
1697
  "text": text,
1689
1698
  "state": state,
1690
1699
  "width": w,
1691
1700
  "height": h,
1692
- "show_border": self.PAR.ops.show_selected_cells_border,
1701
+ "show_border": True,
1693
1702
  "bg": bg,
1694
1703
  "fg": fg,
1695
1704
  "align": self.get_cell_align(c),
@@ -1735,62 +1744,74 @@ class ColumnHeaders(tk.Canvas):
1735
1744
 
1736
1745
  # displayed indexes
1737
1746
  def text_editor_newline_binding(self, r=0, c=0, event: object = None, check_lines=True):
1738
- if self.height_resizing_enabled:
1739
- curr_height = self.text_editor.window.winfo_height()
1740
- if (
1741
- not check_lines
1742
- or self.MT.get_lines_cell_height(
1743
- self.text_editor.window.get_num_lines() + 1,
1744
- font=self.PAR.ops.header_font,
1745
- )
1746
- > curr_height
1747
- ):
1748
- new_height = curr_height + self.MT.header_xtra_lines_increment
1749
- space_bot = self.MT.get_space_bot(0)
1750
- if new_height > space_bot:
1751
- new_height = space_bot
1752
- if new_height != curr_height:
1753
- self.text_editor.window.config(height=new_height)
1754
- self.set_height(new_height, set_TL=True)
1755
- if self.dropdown.open and self.dropdown.get_coords() == c:
1756
- win_h, anchor = self.get_dropdown_height_anchor(c, new_height)
1757
- self.coords(
1758
- self.dropdown.canvas_id,
1759
- self.MT.col_positions[c],
1760
- new_height - 1,
1761
- )
1762
- self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
1747
+ if not self.height_resizing_enabled:
1748
+ return
1749
+ curr_height = self.text_editor.window.winfo_height()
1750
+ if curr_height < self.MT.min_header_height:
1751
+ return
1752
+ if (
1753
+ not check_lines
1754
+ or self.MT.get_lines_cell_height(
1755
+ self.text_editor.window.get_num_lines() + 1,
1756
+ font=self.text_editor.tktext.cget("font"),
1757
+ )
1758
+ > curr_height
1759
+ ):
1760
+ new_height = curr_height + self.MT.header_xtra_lines_increment
1761
+ space_bot = self.MT.get_space_bot(0)
1762
+ if new_height > space_bot:
1763
+ new_height = space_bot
1764
+ if new_height != curr_height:
1765
+ self.text_editor.window.config(height=new_height)
1766
+ self.set_height(new_height, set_TL=True)
1767
+ if self.dropdown.open and self.dropdown.get_coords() == c:
1768
+ win_h, anchor = self.get_dropdown_height_anchor(c, new_height)
1769
+ self.coords(
1770
+ self.dropdown.canvas_id,
1771
+ self.MT.col_positions[c],
1772
+ new_height - 1,
1773
+ )
1774
+ self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
1763
1775
 
1764
- def refresh_open_window_positions(self):
1776
+ def refresh_open_window_positions(self, zoom: Literal["in", "out"]):
1765
1777
  if self.text_editor.open:
1766
1778
  c = self.text_editor.column
1767
- self.text_editor.window.config(height=self.MT.col_positions[c + 1] - self.MT.col_positions[c])
1779
+ self.text_editor.window.config(
1780
+ height=self.current_height,
1781
+ width=self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1,
1782
+ )
1783
+ self.text_editor.tktext.config(font=self.PAR.ops.header_font)
1768
1784
  self.coords(
1769
1785
  self.text_editor.canvas_id,
1770
- 0,
1771
1786
  self.MT.col_positions[c],
1787
+ 0,
1772
1788
  )
1773
1789
  if self.dropdown.open:
1790
+ if zoom == "in":
1791
+ self.dropdown.window.zoom_in()
1792
+ elif zoom == "out":
1793
+ self.dropdown.window.zoom_out()
1774
1794
  c = self.dropdown.get_coords()
1775
1795
  if self.text_editor.open:
1776
1796
  text_editor_h = self.text_editor.window.winfo_height()
1777
1797
  win_h, anchor = self.get_dropdown_height_anchor(c, text_editor_h)
1778
1798
  else:
1779
- text_editor_h = self.MT.col_positions[c + 1] - self.MT.col_positions[c]
1799
+ text_editor_h = self.current_height
1780
1800
  anchor = self.itemcget(self.dropdown.canvas_id, "anchor")
1781
1801
  # win_h = 0
1802
+ self.dropdown.window.config(width=self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1)
1782
1803
  if anchor == "nw":
1783
1804
  self.coords(
1784
1805
  self.dropdown.canvas_id,
1785
- 0,
1786
- self.MT.col_positions[c] + text_editor_h - 1,
1806
+ self.MT.col_positions[c],
1807
+ text_editor_h - 1,
1787
1808
  )
1788
1809
  # self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
1789
1810
  elif anchor == "sw":
1790
1811
  self.coords(
1791
1812
  self.dropdown.canvas_id,
1792
- 0,
1793
1813
  self.MT.col_positions[c],
1814
+ 0,
1794
1815
  )
1795
1816
  # self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
1796
1817
 
@@ -1888,42 +1909,39 @@ class ColumnHeaders(tk.Canvas):
1888
1909
  modified_func(event)
1889
1910
  dd_window.search_and_see(event)
1890
1911
 
1891
- def open_dropdown_window(self, c, datacn=None, event: object = None):
1912
+ def open_dropdown_window(self, c, event: object = None):
1892
1913
  self.hide_text_editor("Escape")
1893
- if datacn is None:
1894
- datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
1895
- kwargs = self.get_cell_kwargs(datacn, key="dropdown")
1914
+ kwargs = self.get_cell_kwargs(self.MT.datacn(c), key="dropdown")
1896
1915
  if kwargs["state"] == "normal":
1897
1916
  if not self.open_text_editor(event=event, c=c, dropdown=True):
1898
1917
  return
1899
1918
  win_h, anchor = self.get_dropdown_height_anchor(c)
1919
+ win_w = self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1
1900
1920
  ypos = self.current_height - 1
1901
- if self.dropdown.window is not None:
1902
- self.dropdown.window.search_function = kwargs["search_function"]
1903
- self.dropdown.window.c = c
1904
- self.dropdown.window.row = -1
1905
- self.dropdown.window.set_options()
1906
- self.dropdown.window.values(kwargs["values"])
1907
- if not self.dropdown.open:
1908
- self.itemconfig(self.dropdown.canvas_id, state="normal")
1921
+ reset_kwargs = {
1922
+ "r": 0,
1923
+ "c": c,
1924
+ "width": win_w,
1925
+ "height": win_h,
1926
+ "font": self.PAR.ops.header_font,
1927
+ "ops": self.PAR.ops,
1928
+ "outline_color": self.PAR.ops.popup_menu_fg,
1929
+ "align": self.get_cell_align(c),
1930
+ "values": kwargs["values"],
1931
+ }
1932
+ if self.dropdown.window:
1933
+ self.dropdown.window.reset(**reset_kwargs)
1934
+ self.itemconfig(self.dropdown.canvas_id, state="normal")
1909
1935
  self.coords(self.dropdown.canvas_id, self.MT.col_positions[c], ypos)
1910
1936
  else:
1911
1937
  self.dropdown.window = self.PAR.dropdown_class(
1912
- self.MT.winfo_toplevel(),
1913
- 0,
1914
- c,
1915
- width=self.MT.col_positions[c + 1] - self.MT.col_positions[c] + 1,
1916
- height=win_h,
1917
- font=self.PAR.ops.header_font,
1918
- ops=self.PAR.ops,
1919
- outline_color=self.PAR.ops.popup_menu_fg,
1920
- values=kwargs["values"],
1938
+ self.winfo_toplevel(),
1939
+ **reset_kwargs,
1940
+ single_index="c",
1921
1941
  close_dropdown_window=self.close_dropdown_window,
1922
1942
  search_function=kwargs["search_function"],
1923
1943
  arrowkey_RIGHT=self.MT.arrowkey_RIGHT,
1924
1944
  arrowkey_LEFT=self.MT.arrowkey_LEFT,
1925
- align="w",
1926
- single_index="c",
1927
1945
  )
1928
1946
  self.dropdown.canvas_id = self.create_window(
1929
1947
  (self.MT.col_positions[c], ypos),
tksheet/functions.py CHANGED
@@ -245,6 +245,12 @@ def is_iterable(o: object) -> bool:
245
245
  return False
246
246
 
247
247
 
248
+ def int_x_iter(i: Iterator[int] | int) -> Iterator[int]:
249
+ if isinstance(i, int):
250
+ return (i,)
251
+ return i
252
+
253
+
248
254
  def unpack(t: tuple[object] | tuple[Iterator[object]]) -> tuple[object]:
249
255
  if not len(t):
250
256
  return t
@@ -345,21 +351,27 @@ def get_seq_without_gaps_at_index(
345
351
  return seq
346
352
 
347
353
 
348
- def consecutive_chunks(seq: list[object]) -> Generator[object]:
349
- if not seq:
350
- yield seq
354
+ def consecutive_chunks(seq: list[int]) -> Generator[list[int]]:
351
355
  start = 0
352
- end = 0
353
- for index, value in enumerate(seq):
354
- if index < len(seq) - 1:
355
- if seq[index + 1] > value + 1:
356
- end = index + 1
357
- yield seq[start:end]
358
- start = end
359
- else:
356
+ for index, value in enumerate(seq, 1):
357
+ try:
358
+ if seq[index] > value + 1:
359
+ yield seq[start:(start := index)]
360
+ except Exception:
360
361
  yield seq[start : len(seq)]
361
362
 
362
363
 
364
+ def consecutive_ranges(seq: Sequence[int]) -> Generator[tuple[int, int]]:
365
+ start = 0
366
+ for index, value in enumerate(seq, 1):
367
+ try:
368
+ if seq[index] > value + 1:
369
+ yield seq[start], seq[index - 1] + 1
370
+ start = index
371
+ except Exception:
372
+ yield seq[start], seq[-1] + 1
373
+
374
+
363
375
  def is_contiguous(seq: list[int]) -> bool:
364
376
  itr = iter(seq)
365
377
  prev = next(itr)
@@ -1146,6 +1158,22 @@ def set_readonly(
1146
1158
  return options
1147
1159
 
1148
1160
 
1161
+ def convert_align(align: str | None) -> str | None:
1162
+ if isinstance(align, str):
1163
+ a = align.lower()
1164
+ if a == "global":
1165
+ return None
1166
+ elif a in ("c", "center", "centre"):
1167
+ return "center"
1168
+ elif a in ("w", "west", "left"):
1169
+ return "w"
1170
+ elif a in ("e", "east", "right"):
1171
+ return "e"
1172
+ elif align is None:
1173
+ return None
1174
+ raise ValueError("Align must be one of the following values: c, center, w, west, left, e, east, right")
1175
+
1176
+
1149
1177
  def set_align(
1150
1178
  options: dict,
1151
1179
  key: int | tuple[int, int],