tksheet 7.1.20__py3-none-any.whl → 7.1.22__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.20"
7
+ __version__ = "7.1.22"
8
8
 
9
9
  from .colors import (
10
10
  color_map,
@@ -32,6 +32,7 @@ from .formatters import (
32
32
  try_to_bool,
33
33
  )
34
34
  from .functions import (
35
+ add_highlight,
35
36
  alpha2idx,
36
37
  alpha2num,
37
38
  consecutive_chunks,
@@ -42,6 +43,7 @@ from .functions import (
42
43
  event_dict,
43
44
  get_checkbox_dict,
44
45
  get_checkbox_kwargs,
46
+ get_csv_str_dialect,
45
47
  get_data_from_clipboard,
46
48
  get_dropdown_dict,
47
49
  get_dropdown_kwargs,
@@ -54,6 +56,7 @@ from .functions import (
54
56
  is_iterable,
55
57
  move_elements_by_mapping,
56
58
  move_elements_to,
59
+ new_tk_event,
57
60
  num2alpha,
58
61
  rounded_box_coords,
59
62
  span_dict,
@@ -66,6 +69,7 @@ from .other_classes import (
66
69
  DrawnItem,
67
70
  EventDataDict,
68
71
  GeneratedMouseEvent,
72
+ Highlight,
69
73
  Selected,
70
74
  Span,
71
75
  SpanRange,
tksheet/column_headers.py CHANGED
@@ -25,6 +25,7 @@ from .functions import (
25
25
  event_dict,
26
26
  get_n2a,
27
27
  is_contiguous,
28
+ new_tk_event,
28
29
  pickled_event_dict,
29
30
  rounded_box_coords,
30
31
  try_binding,
@@ -42,6 +43,8 @@ from .vars import (
42
43
  USER_OS,
43
44
  rc_binding,
44
45
  symbols_set,
46
+ text_editor_close_bindings,
47
+ text_editor_newline_bindings,
45
48
  text_editor_to_unbind,
46
49
  )
47
50
 
@@ -124,6 +127,13 @@ class ColumnHeaders(tk.Canvas):
124
127
  self.align = kwargs["header_align"]
125
128
  self.basic_bindings()
126
129
 
130
+ def event_generate(self, *args, **kwargs) -> None:
131
+ for arg in args:
132
+ if self.MT and arg in self.MT.event_linker:
133
+ self.MT.event_linker[arg]()
134
+ else:
135
+ super().event_generate(*args, **kwargs)
136
+
127
137
  def basic_bindings(self, enable: bool = True):
128
138
  if enable:
129
139
  self.bind("<Motion>", self.mouse_motion)
@@ -833,6 +843,7 @@ class ColumnHeaders(tk.Canvas):
833
843
  event_data = event_dict(
834
844
  name="move_columns",
835
845
  sheet=self.PAR.name,
846
+ widget=self,
836
847
  boxes=self.MT.get_boxes(),
837
848
  selected=self.MT.selected,
838
849
  value=c,
@@ -844,6 +855,7 @@ class ColumnHeaders(tk.Canvas):
844
855
  to_move=self.dragged_col.to_move,
845
856
  ),
846
857
  move_data=self.PAR.ops.column_drag_and_drop_perform,
858
+ move_widths=self.PAR.ops.column_drag_and_drop_perform,
847
859
  event_data=event_data,
848
860
  )
849
861
  event_data["moved"]["columns"] = {
@@ -1284,12 +1296,9 @@ class ColumnHeaders(tk.Canvas):
1284
1296
  self.itemconfig(t, fill=fill, tag=tag, state="normal")
1285
1297
  self.lift(t)
1286
1298
  else:
1287
- t = self.create_line(
1299
+ t = self.create_polygon(
1288
1300
  points,
1289
1301
  fill=fill,
1290
- width=2,
1291
- capstyle=tk.ROUND,
1292
- joinstyle=tk.ROUND,
1293
1302
  tag=tag,
1294
1303
  )
1295
1304
  self.disp_dropdown[t] = True
@@ -1733,21 +1742,16 @@ class ColumnHeaders(tk.Canvas):
1733
1742
  self.itemconfig(self.text_editor.canvas_id, state="normal")
1734
1743
  self.text_editor.open = True
1735
1744
  self.coords(self.text_editor.canvas_id, x, y)
1745
+ for b in text_editor_newline_bindings:
1746
+ self.text_editor.tktext.bind(b, self.text_editor_newline_binding)
1747
+ for b in text_editor_close_bindings:
1748
+ self.text_editor.tktext.bind(b, self.close_text_editor)
1736
1749
  if not dropdown:
1737
1750
  self.text_editor.tktext.focus_set()
1738
1751
  self.text_editor.window.scroll_to_bottom()
1739
- self.text_editor.tktext.bind("<Alt-Return>", lambda _x: self.text_editor_newline_binding(c=c))
1740
- self.text_editor.tktext.bind("<Alt-KP_Enter>", lambda _x: self.text_editor_newline_binding(c=c))
1741
- if USER_OS == "darwin":
1742
- self.text_editor.tktext.bind("<Option-Return>", lambda _x: self.text_editor_newline_binding(c=c))
1752
+ self.text_editor.tktext.bind("<FocusOut>", self.close_text_editor)
1743
1753
  for key, func in self.MT.text_editor_user_bound_keys.items():
1744
1754
  self.text_editor.tktext.bind(key, func)
1745
- self.text_editor.tktext.bind("<Tab>", lambda _x: self.close_text_editor((c, "Tab")))
1746
- self.text_editor.tktext.bind("<Return>", lambda _x: self.close_text_editor((c, "Return")))
1747
- self.text_editor.tktext.bind("<KP_Enter>", lambda _x: self.close_text_editor((c, "Return")))
1748
- if not dropdown:
1749
- self.text_editor.tktext.bind("<FocusOut>", lambda _x: self.close_text_editor((c, "FocusOut")))
1750
- self.text_editor.tktext.bind("<Escape>", lambda _x: self.close_text_editor((c, "Escape")))
1751
1755
  return True
1752
1756
 
1753
1757
  # displayed indexes #just here to receive text editor arg
@@ -1766,7 +1770,7 @@ class ColumnHeaders(tk.Canvas):
1766
1770
  self.coords(self.text_editor.canvas_id, self.MT.col_positions[c] + 1, 0)
1767
1771
 
1768
1772
  # displayed indexes
1769
- def text_editor_newline_binding(self, r=0, c=0, event: object = None, check_lines=True):
1773
+ def text_editor_newline_binding(self, event: object = None, check_lines=True):
1770
1774
  if not self.height_resizing_enabled:
1771
1775
  return
1772
1776
  curr_height = self.text_editor.window.winfo_height()
@@ -1780,6 +1784,7 @@ class ColumnHeaders(tk.Canvas):
1780
1784
  )
1781
1785
  > curr_height
1782
1786
  ):
1787
+ c = self.text_editor.column
1783
1788
  new_height = curr_height + self.MT.header_xtra_lines_increment
1784
1789
  space_bot = self.MT.get_space_bot(0)
1785
1790
  if new_height > space_bot:
@@ -1848,31 +1853,33 @@ class ColumnHeaders(tk.Canvas):
1848
1853
  self.focus_set()
1849
1854
 
1850
1855
  # c is displayed col
1851
- def close_text_editor(
1852
- self,
1853
- editor_info: tuple,
1854
- ):
1856
+ def close_text_editor(self, event: tk.Event) -> Literal["break"] | None:
1855
1857
  # checking if text editor should be closed or not
1856
- focused = self.focus_get()
1858
+ # errors if __tk_filedialog is open
1859
+ try:
1860
+ focused = self.focus_get()
1861
+ except Exception:
1862
+ focused = None
1857
1863
  try:
1858
1864
  if focused == self.text_editor.tktext.rc_popup_menu:
1859
1865
  return "break"
1860
1866
  except Exception:
1861
1867
  pass
1862
- if focused is None and editor_info:
1868
+ if focused is None:
1863
1869
  return "break"
1864
- if editor_info[1] == "Escape":
1870
+ if event.keysym == "Escape":
1865
1871
  self.hide_text_editor_and_dropdown()
1866
1872
  return
1867
1873
  # setting cell data with text editor value
1868
1874
  text_editor_value = self.text_editor.get()
1869
- c = editor_info[0]
1875
+ c = self.text_editor.column
1870
1876
  datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
1871
1877
  event_data = event_dict(
1872
1878
  name="end_edit_header",
1873
1879
  sheet=self.PAR.name,
1880
+ widget=self,
1874
1881
  cells_header={datacn: self.get_cell_data(datacn)},
1875
- key=editor_info[1] if len(editor_info) >= 2 else "FocusOut",
1882
+ key=event.keysym,
1876
1883
  value=text_editor_value,
1877
1884
  loc=c,
1878
1885
  column=c,
@@ -1896,7 +1903,7 @@ class ColumnHeaders(tk.Canvas):
1896
1903
  try_binding(self.extra_end_edit_cell_func, event_data)
1897
1904
  self.MT.recreate_all_selection_boxes()
1898
1905
  self.hide_text_editor_and_dropdown()
1899
- if editor_info[1] != "FocusOut":
1906
+ if event.keysym != "FocusOut":
1900
1907
  self.focus_set()
1901
1908
  return "break"
1902
1909
 
@@ -2017,6 +2024,7 @@ class ColumnHeaders(tk.Canvas):
2017
2024
  event_data = event_dict(
2018
2025
  name="end_edit_header",
2019
2026
  sheet=self.PAR.name,
2027
+ widget=self,
2020
2028
  cells_header={datacn: pre_edit_value},
2021
2029
  key="??",
2022
2030
  value=selection,
@@ -2048,7 +2056,7 @@ class ColumnHeaders(tk.Canvas):
2048
2056
  def mouseclick_outside_editor_or_dropdown(self, inside: bool = False):
2049
2057
  closed_dd_coords = self.dropdown.get_coords()
2050
2058
  if self.text_editor.open:
2051
- self.close_text_editor((self.text_editor.column, "ButtonPress-1"))
2059
+ self.close_text_editor(new_tk_event("ButtonPress-1"))
2052
2060
  if closed_dd_coords is not None:
2053
2061
  self.hide_dropdown_window()
2054
2062
  if inside:
@@ -2086,6 +2094,7 @@ class ColumnHeaders(tk.Canvas):
2086
2094
  event_data = event_dict(
2087
2095
  name="edit_header",
2088
2096
  sheet=self.PAR.name,
2097
+ widget=self,
2089
2098
  cells_header={datacn: self.get_cell_data(datacn)},
2090
2099
  boxes=self.MT.get_boxes(),
2091
2100
  selected=self.MT.selected,
@@ -2243,6 +2252,7 @@ class ColumnHeaders(tk.Canvas):
2243
2252
  event_data = event_dict(
2244
2253
  name="end_edit_header",
2245
2254
  sheet=self.PAR.name,
2255
+ widget=self,
2246
2256
  cells_header={datacn: pre_edit_value},
2247
2257
  key="??",
2248
2258
  value=value,
tksheet/functions.py CHANGED
@@ -17,6 +17,9 @@ from collections.abc import (
17
17
  from functools import partial
18
18
  from itertools import islice, repeat
19
19
 
20
+ from .formatters import (
21
+ to_bool,
22
+ )
20
23
  from .other_classes import (
21
24
  Box_nt,
22
25
  DotDict,
@@ -31,16 +34,20 @@ pickle_obj = partial(pickle.dumps, protocol=pickle.HIGHEST_PROTOCOL)
31
34
  unpickle_obj = pickle.loads
32
35
 
33
36
 
37
+ def get_csv_str_dialect(s: str, delimiters: str) -> csv.Dialect:
38
+ try:
39
+ return csv.Sniffer().sniff(s[:5000] if len(s) > 5000 else s, delimiters=delimiters)
40
+ except Exception:
41
+ return csv.excel_tab
42
+
43
+
34
44
  def get_data_from_clipboard(
35
45
  widget: tk.Misc,
36
46
  delimiters: str,
37
47
  lineterminator: str = "\n",
38
48
  ) -> list[list[str]]:
39
49
  data = widget.clipboard_get()
40
- try:
41
- dialect = csv.Sniffer().sniff(data, delimiters=delimiters)
42
- except Exception:
43
- dialect = csv.excel_tab
50
+ dialect = get_csv_str_dialect(data, delimiters=delimiters)
44
51
  if dialect.delimiter in data or lineterminator in data:
45
52
  return list(csv.reader(io.StringIO(data), dialect=dialect, skipinitialspace=True))
46
53
  return [[data]]
@@ -59,6 +66,12 @@ def tksheet_type_error(kwarg: str, valid_types: list[str], not_type: object) ->
59
66
  return f"Argument '{kwarg}' must be one of the following types: {valid_types}, " f"not {type(not_type)}."
60
67
 
61
68
 
69
+ def new_tk_event(keysym: str) -> tk.Event:
70
+ event = tk.Event()
71
+ event.keysym = keysym
72
+ return event
73
+
74
+
62
75
  def dropdown_search_function(
63
76
  search_for: object,
64
77
  data: Sequence[object],
@@ -112,6 +125,7 @@ def selection_box_tup_to_dict(box: tuple) -> dict:
112
125
  def event_dict(
113
126
  name: str = None,
114
127
  sheet: object = None,
128
+ widget: tk.Canvas | None = None,
115
129
  boxes: None | dict | tuple = None,
116
130
  cells_table: None | dict = None,
117
131
  cells_header: None | dict = None,
@@ -176,6 +190,7 @@ def event_dict(
176
190
  # "header": DotDict() if resized_header is None else resized_header,
177
191
  # "index": DotDict() if resized_index is None else resized_index,
178
192
  ),
193
+ widget=widget,
179
194
  )
180
195
 
181
196
 
@@ -184,7 +199,7 @@ def change_eventname(event_dict: EventDataDict, newname: str) -> EventDataDict:
184
199
 
185
200
 
186
201
  def pickled_event_dict(d: DotDict) -> DotDict:
187
- return DotDict(name=d["eventname"], data=pickle_compress(d))
202
+ return DotDict(name=d["eventname"], data=pickle_compress(DotDict({k: v for k, v in d.items() if k != "widget"})))
188
203
 
189
204
 
190
205
  def len_to_idx(n: int) -> int:
@@ -281,6 +296,13 @@ def is_type_int(o: object) -> bool:
281
296
  return isinstance(o, int) and not isinstance(o, bool)
282
297
 
283
298
 
299
+ def force_bool(o: object) -> bool:
300
+ try:
301
+ return to_bool(o)
302
+ except Exception:
303
+ return False
304
+
305
+
284
306
  def str_to_coords(s: str) -> None | tuple[int]:
285
307
  s = s.split(":")
286
308