tksheet 7.1.6__py3-none-any.whl → 7.1.8__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
@@ -1,96 +1,97 @@
1
- # ruff: noqa: F401
2
-
3
- """
4
- tksheet - A Python tkinter table widget
5
- """
6
-
7
- __version__ = "7.1.6"
8
-
9
- from .colors import (
10
- color_map,
11
- )
12
- from .column_headers import ColumnHeaders
13
- from .formatters import (
14
- Formatter,
15
- bool_formatter,
16
- data_to_str,
17
- float_formatter,
18
- float_to_str,
19
- format_data,
20
- formatter,
21
- get_clipboard_data,
22
- get_data_with_valid_check,
23
- int_formatter,
24
- is_bool_like,
25
- is_none_like,
26
- percentage_formatter,
27
- percentage_to_str,
28
- to_bool,
29
- to_float,
30
- to_int,
31
- to_str,
32
- try_to_bool,
33
- )
34
- from .functions import (
35
- alpha2idx,
36
- alpha2num,
37
- consecutive_chunks,
38
- data_to_displayed_idxs,
39
- displayed_to_data_idxs,
40
- dropdown_search_function,
41
- event_dict,
42
- get_checkbox_dict,
43
- get_checkbox_kwargs,
44
- get_checkbox_points,
45
- get_dropdown_dict,
46
- get_dropdown_kwargs,
47
- get_index_of_gap_in_sorted_integer_seq_forward,
48
- get_index_of_gap_in_sorted_integer_seq_reverse,
49
- get_n2a,
50
- get_new_indexes,
51
- get_seq_without_gaps_at_index,
52
- is_iterable,
53
- move_elements_by_mapping,
54
- move_elements_to,
55
- num2alpha,
56
- span_dict,
57
- tksheet_type_error,
58
- )
59
- from .main_table import MainTable
60
- from .other_classes import (
61
- DotDict,
62
- DraggedRowColumn,
63
- DrawnItem,
64
- EventDataDict,
65
- GeneratedMouseEvent,
66
- Selected,
67
- Span,
68
- SpanRange,
69
- TextCfg,
70
- )
71
- from .row_index import RowIndex
72
- from .sheet import Dropdown, Sheet
73
- from .sheet_options import new_sheet_options
74
- from .text_editor import (
75
- TextEditor,
76
- TextEditorTkText,
77
- )
78
- from .themes import (
79
- theme_black,
80
- theme_dark,
81
- theme_dark_blue,
82
- theme_dark_green,
83
- theme_light_blue,
84
- theme_light_green,
85
- )
86
- from .top_left_rectangle import TopLeftRectangle
87
- from .vars import (
88
- USER_OS,
89
- ctrl_key,
90
- emitted_events,
91
- falsy,
92
- nonelike,
93
- rc_binding,
94
- symbols_set,
95
- truthy,
96
- )
1
+ # ruff: noqa: F401
2
+
3
+ """
4
+ tksheet - A Python tkinter table widget
5
+ """
6
+
7
+ __version__ = "7.1.8"
8
+
9
+ from .colors import (
10
+ color_map,
11
+ )
12
+ from .column_headers import ColumnHeaders
13
+ from .formatters import (
14
+ Formatter,
15
+ bool_formatter,
16
+ data_to_str,
17
+ float_formatter,
18
+ float_to_str,
19
+ format_data,
20
+ formatter,
21
+ get_clipboard_data,
22
+ get_data_with_valid_check,
23
+ int_formatter,
24
+ is_bool_like,
25
+ is_none_like,
26
+ percentage_formatter,
27
+ percentage_to_str,
28
+ to_bool,
29
+ to_float,
30
+ to_int,
31
+ to_str,
32
+ try_to_bool,
33
+ )
34
+ from .functions import (
35
+ alpha2idx,
36
+ alpha2num,
37
+ consecutive_chunks,
38
+ consecutive_ranges,
39
+ data_to_displayed_idxs,
40
+ displayed_to_data_idxs,
41
+ dropdown_search_function,
42
+ event_dict,
43
+ get_checkbox_dict,
44
+ get_checkbox_kwargs,
45
+ get_dropdown_dict,
46
+ get_dropdown_kwargs,
47
+ get_index_of_gap_in_sorted_integer_seq_forward,
48
+ get_index_of_gap_in_sorted_integer_seq_reverse,
49
+ get_n2a,
50
+ get_new_indexes,
51
+ get_seq_without_gaps_at_index,
52
+ is_iterable,
53
+ move_elements_by_mapping,
54
+ move_elements_to,
55
+ num2alpha,
56
+ rounded_box_coords,
57
+ span_dict,
58
+ tksheet_type_error,
59
+ )
60
+ from .main_table import MainTable
61
+ from .other_classes import (
62
+ DotDict,
63
+ DraggedRowColumn,
64
+ DrawnItem,
65
+ EventDataDict,
66
+ GeneratedMouseEvent,
67
+ Selected,
68
+ Span,
69
+ SpanRange,
70
+ TextCfg,
71
+ )
72
+ from .row_index import RowIndex
73
+ from .sheet import Dropdown, Sheet
74
+ from .sheet_options import new_sheet_options
75
+ from .text_editor import (
76
+ TextEditor,
77
+ TextEditorTkText,
78
+ )
79
+ from .themes import (
80
+ theme_black,
81
+ theme_dark,
82
+ theme_dark_blue,
83
+ theme_dark_green,
84
+ theme_light_blue,
85
+ theme_light_green,
86
+ )
87
+ from .top_left_rectangle import TopLeftRectangle
88
+ from .vars import (
89
+ USER_OS,
90
+ ctrl_key,
91
+ emitted_events,
92
+ falsy,
93
+ nonelike,
94
+ rc_binding,
95
+ symbols_set,
96
+ truthy,
97
+ )
tksheet/column_headers.py CHANGED
@@ -23,9 +23,9 @@ from .functions import (
23
23
  consecutive_ranges,
24
24
  ev_stack_dict,
25
25
  event_dict,
26
- get_checkbox_points,
27
26
  get_n2a,
28
27
  is_contiguous,
28
+ rounded_box_coords,
29
29
  try_binding,
30
30
  )
31
31
  from .other_classes import (
@@ -41,6 +41,7 @@ from .vars import (
41
41
  USER_OS,
42
42
  rc_binding,
43
43
  symbols_set,
44
+ text_editor_to_unbind,
44
45
  )
45
46
 
46
47
 
@@ -935,14 +936,26 @@ class ColumnHeaders(tk.Canvas):
935
936
  outline: str,
936
937
  state: str,
937
938
  tags: str | tuple[str],
939
+ iid: None | int = None,
938
940
  ) -> int:
939
- if self.hidd_boxes:
940
- iid = self.hidd_boxes.pop()
941
- self.coords(iid, x1, y1, x2, y2)
941
+ coords = rounded_box_coords(
942
+ x1,
943
+ y1,
944
+ x2,
945
+ y2,
946
+ radius=8 if self.PAR.ops.rounded_boxes else 0,
947
+ )
948
+ if isinstance(iid, int):
949
+ self.coords(iid, coords)
942
950
  self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags)
943
951
  else:
944
- iid = self.create_rectangle(x1, y1, x2, y2, fill=fill, outline=outline, state=state, tags=tags)
945
- self.disp_boxes.add(iid)
952
+ if self.hidd_boxes:
953
+ iid = self.hidd_boxes.pop()
954
+ self.coords(iid, coords)
955
+ self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags)
956
+ else:
957
+ iid = self.create_polygon(coords, fill=fill, outline=outline, state=state, tags=tags, smooth=True)
958
+ self.disp_boxes.add(iid)
946
959
  return iid
947
960
 
948
961
  def hide_box(self, item: int) -> None:
@@ -1276,7 +1289,7 @@ class ColumnHeaders(tk.Canvas):
1276
1289
  self.disp_dropdown[t] = True
1277
1290
 
1278
1291
  def redraw_checkbox(self, x1, y1, x2, y2, fill, outline, tag, draw_check=False):
1279
- points = get_checkbox_points(x1, y1, x2, y2)
1292
+ points = rounded_box_coords(x1, y1, x2, y2)
1280
1293
  if self.hidd_checkbox:
1281
1294
  t, sh = self.hidd_checkbox.popitem()
1282
1295
  self.coords(t, points)
@@ -1294,7 +1307,7 @@ class ColumnHeaders(tk.Canvas):
1294
1307
  y1 = y1 + 4
1295
1308
  x2 = x2 - 3
1296
1309
  y2 = y2 - 3
1297
- points = get_checkbox_points(x1, y1, x2, y2, radius=4)
1310
+ points = rounded_box_coords(x1, y1, x2, y2, radius=4)
1298
1311
  if self.hidd_checkbox:
1299
1312
  t, sh = self.hidd_checkbox.popitem()
1300
1313
  self.coords(t, points)
@@ -1574,16 +1587,14 @@ class ColumnHeaders(tk.Canvas):
1574
1587
  dct[iid] = False
1575
1588
  return True
1576
1589
 
1577
- def get_redraw_selections(self, startc, endc):
1578
- d = defaultdict(list)
1590
+ def get_redraw_selections(self, startc: int, endc: int) -> dict[str, set[int]]:
1591
+ d = defaultdict(set)
1579
1592
  for item, box in self.MT.get_selection_items(rows=False):
1580
- d[box.type_].append(box.coords)
1581
- d2 = {}
1582
- if "cells" in d:
1583
- d2["cells"] = {c for c in range(startc, endc) for r1, c1, r2, c2 in d["cells"] if c1 <= c and c2 > c}
1584
- if "columns" in d:
1585
- d2["columns"] = {c for c in range(startc, endc) for r1, c1, r2, c2 in d["columns"] if c1 <= c and c2 > c}
1586
- return d2
1593
+ r1, c1, r2, c2 = box.coords
1594
+ for c in range(startc, endc):
1595
+ if c1 <= c and c2 > c:
1596
+ d[box.type_].add(c)
1597
+ return d
1587
1598
 
1588
1599
  def open_cell(self, event: object = None, ignore_existing_editor=False):
1589
1600
  if not self.MT.anything_selected() or (not ignore_existing_editor and self.text_editor.open):
@@ -1653,6 +1664,7 @@ class ColumnHeaders(tk.Canvas):
1653
1664
  key=extra_func_key,
1654
1665
  value=text,
1655
1666
  loc=c,
1667
+ column=c,
1656
1668
  boxes=self.MT.get_boxes(),
1657
1669
  selected=self.MT.selected,
1658
1670
  )
@@ -1716,12 +1728,14 @@ class ColumnHeaders(tk.Canvas):
1716
1728
  self.text_editor.tktext.focus_set()
1717
1729
  self.text_editor.window.scroll_to_bottom()
1718
1730
  self.text_editor.tktext.bind("<Alt-Return>", lambda _x: self.text_editor_newline_binding(c=c))
1731
+ self.text_editor.tktext.bind("<Alt-KP_Enter>", lambda _x: self.text_editor_newline_binding(c=c))
1719
1732
  if USER_OS == "darwin":
1720
1733
  self.text_editor.tktext.bind("<Option-Return>", lambda _x: self.text_editor_newline_binding(c=c))
1721
1734
  for key, func in self.MT.text_editor_user_bound_keys.items():
1722
1735
  self.text_editor.tktext.bind(key, func)
1723
1736
  self.text_editor.tktext.bind("<Tab>", lambda _x: self.close_text_editor((c, "Tab")))
1724
1737
  self.text_editor.tktext.bind("<Return>", lambda _x: self.close_text_editor((c, "Return")))
1738
+ self.text_editor.tktext.bind("<KP_Enter>", lambda _x: self.close_text_editor((c, "Return")))
1725
1739
  if not dropdown:
1726
1740
  self.text_editor.tktext.bind("<FocusOut>", lambda _x: self.close_text_editor((c, "FocusOut")))
1727
1741
  self.text_editor.tktext.bind("<Escape>", lambda _x: self.close_text_editor((c, "Escape")))
@@ -1817,6 +1831,8 @@ class ColumnHeaders(tk.Canvas):
1817
1831
 
1818
1832
  def hide_text_editor(self, reason: None | str = None) -> None:
1819
1833
  if self.text_editor.open:
1834
+ for binding in text_editor_to_unbind:
1835
+ self.text_editor.tktext.unbind(binding)
1820
1836
  self.itemconfig(self.text_editor.canvas_id, state="hidden")
1821
1837
  self.text_editor.open = False
1822
1838
  if reason == "Escape":
@@ -1840,7 +1856,7 @@ class ColumnHeaders(tk.Canvas):
1840
1856
  self.hide_text_editor_and_dropdown()
1841
1857
  return
1842
1858
  # setting cell data with text editor value
1843
- self.text_editor_value = self.text_editor.get()
1859
+ text_editor_value = self.text_editor.get()
1844
1860
  c = editor_info[0]
1845
1861
  datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
1846
1862
  event_data = event_dict(
@@ -1848,8 +1864,9 @@ class ColumnHeaders(tk.Canvas):
1848
1864
  sheet=self.PAR.name,
1849
1865
  cells_header={datacn: self.get_cell_data(datacn)},
1850
1866
  key=editor_info[1] if len(editor_info) >= 2 else "FocusOut",
1851
- value=self.text_editor_value,
1867
+ value=text_editor_value,
1852
1868
  loc=c,
1869
+ column=c,
1853
1870
  boxes=self.MT.get_boxes(),
1854
1871
  selected=self.MT.selected,
1855
1872
  )
@@ -1861,11 +1878,11 @@ class ColumnHeaders(tk.Canvas):
1861
1878
  check_input_valid=False,
1862
1879
  )
1863
1880
  if self.MT.edit_validation_func:
1864
- self.text_editor_value = self.MT.edit_validation_func(event_data)
1865
- if self.text_editor_value is not None and self.input_valid_for_cell(datacn, self.text_editor_value):
1866
- edited = set_data(value=self.text_editor_value)
1867
- elif self.input_valid_for_cell(datacn, self.text_editor_value):
1868
- edited = set_data(value=self.text_editor_value)
1881
+ text_editor_value = self.MT.edit_validation_func(event_data)
1882
+ if text_editor_value is not None and self.input_valid_for_cell(datacn, text_editor_value):
1883
+ edited = set_data(value=text_editor_value)
1884
+ elif self.input_valid_for_cell(datacn, text_editor_value):
1885
+ edited = set_data(value=text_editor_value)
1869
1886
  if edited:
1870
1887
  try_binding(self.extra_end_edit_cell_func, event_data)
1871
1888
  self.MT.recreate_all_selection_boxes()
@@ -1958,6 +1975,7 @@ class ColumnHeaders(tk.Canvas):
1958
1975
  sheet=self.PAR.name,
1959
1976
  value=self.text_editor.get(),
1960
1977
  loc=c,
1978
+ column=c,
1961
1979
  boxes=self.MT.get_boxes(),
1962
1980
  selected=self.MT.selected,
1963
1981
  ),
@@ -1993,6 +2011,7 @@ class ColumnHeaders(tk.Canvas):
1993
2011
  key="??",
1994
2012
  value=selection,
1995
2013
  loc=c,
2014
+ column=c,
1996
2015
  boxes=self.MT.get_boxes(),
1997
2016
  selected=self.MT.selected,
1998
2017
  )
@@ -2037,6 +2056,7 @@ class ColumnHeaders(tk.Canvas):
2037
2056
 
2038
2057
  def hide_dropdown_window(self) -> None:
2039
2058
  if self.dropdown.open:
2059
+ self.dropdown.window.unbind("<FocusOut>")
2040
2060
  self.itemconfig(self.dropdown.canvas_id, state="hidden")
2041
2061
  self.dropdown.open = False
2042
2062
 
@@ -2217,6 +2237,7 @@ class ColumnHeaders(tk.Canvas):
2217
2237
  key="??",
2218
2238
  value=value,
2219
2239
  loc=c,
2240
+ column=c,
2220
2241
  boxes=self.MT.get_boxes(),
2221
2242
  selected=self.MT.selected,
2222
2243
  )
tksheet/functions.py CHANGED
@@ -102,6 +102,8 @@ def event_dict(
102
102
  key: None | str = None,
103
103
  value: object = None,
104
104
  loc: None | int | tuple[int] = None,
105
+ row: None | int = None,
106
+ column: None | int = None,
105
107
  resized_rows: None | dict = None,
106
108
  resized_columns: None | dict = None,
107
109
  # resized_index: None, dict] = None,
@@ -147,6 +149,8 @@ def event_dict(
147
149
  key="" if key is None else key,
148
150
  value=None if value is None else value,
149
151
  loc=tuple() if loc is None else loc,
152
+ row=row,
153
+ column=column,
150
154
  resized=DotDict(
151
155
  rows=DotDict() if resized_rows is None else resized_rows,
152
156
  columns=DotDict() if resized_columns is None else resized_columns,
@@ -356,7 +360,7 @@ def consecutive_chunks(seq: list[int]) -> Generator[list[int]]:
356
360
  for index, value in enumerate(seq, 1):
357
361
  try:
358
362
  if seq[index] > value + 1:
359
- yield seq[start:(start := index)]
363
+ yield seq[start : (start := index)]
360
364
  except Exception:
361
365
  yield seq[start : len(seq)]
362
366
 
@@ -403,8 +407,8 @@ def index_exists(seq: Sequence[object], index: int) -> bool:
403
407
 
404
408
  def move_elements_by_mapping(
405
409
  seq: list[object],
406
- new_idxs: dict,
407
- old_idxs: dict,
410
+ new_idxs: dict[int, int],
411
+ old_idxs: dict[int, int],
408
412
  ) -> list[object]:
409
413
  # move elements of a list around, displacing
410
414
  # other elements based on mapping
@@ -472,8 +476,7 @@ def get_new_indexes(
472
476
 
473
477
 
474
478
  def insert_items(seq: list | tuple, to_insert: dict, seq_len_func: Callable | None = None) -> list:
475
- # faster method of inserting many items into a list
476
- # using a dict of reverse sorted order of
479
+ # inserts many items into a list using a dict of reverse sorted order of
477
480
  # {index: value, index: value, ...}
478
481
  res = []
479
482
  extended = 0
@@ -504,14 +507,14 @@ def displayed_to_data_idxs(
504
507
  return [displayed[e] for e in to_convert]
505
508
 
506
509
 
507
- def get_checkbox_points(
510
+ def rounded_box_coords(
508
511
  x1: float,
509
512
  y1: float,
510
513
  x2: float,
511
514
  y2: float,
512
515
  radius: int = 8,
513
- ) -> list[float]:
514
- return [
516
+ ) -> tuple[float]:
517
+ return (
515
518
  x1 + radius,
516
519
  y1,
517
520
  x1 + radius,
@@ -552,7 +555,7 @@ def get_checkbox_points(
552
555
  y1 + radius,
553
556
  x1,
554
557
  y1,
555
- ]
558
+ )
556
559
 
557
560
 
558
561
  def diff_list(seq: list[float]) -> list[int]: