tksheet 7.3.3__py3-none-any.whl → 7.4.0__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/constants.py CHANGED
@@ -9,6 +9,7 @@ symbols_set: set[str] = set("""!#$%&'()*+,-./:;"@[]^_`{|}~>?= \\""")
9
9
  nonelike: set[object] = {None, "none", ""}
10
10
  truthy: set[object] = {True, "true", "t", "yes", "y", "on", "1", 1, 1.0}
11
11
  falsy: set[object] = {False, "false", "f", "no", "n", "off", "0", 0, 0.0}
12
+ _test_str: str = "aiW_-|"
12
13
 
13
14
  val_modifying_options: set[str] = {"checkbox", "format", "dropdown"}
14
15
 
@@ -34,6 +35,18 @@ emitted_events: set[str] = {
34
35
  "<<SelectAll>>",
35
36
  }
36
37
 
38
+ align_helper: dict[str, str] = {
39
+ "w": "nw",
40
+ "e": "ne",
41
+ "center": "n",
42
+ "n": "center",
43
+ "nw": "left",
44
+ "ne": "right",
45
+ }
46
+
47
+ align_value_error: str = "Align must be one of the following values: c, center, w, nw, west, left, e, ne, east, right"
48
+ font_value_error: str = "Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
49
+
37
50
  backwards_compatibility_keys: dict[str, str] = {
38
51
  "font": "table_font",
39
52
  }
tksheet/find_window.py CHANGED
@@ -1,21 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import tkinter as tk
4
- from collections.abc import (
5
- Callable,
6
- )
4
+ from collections.abc import Callable
7
5
  from typing import Literal
8
6
 
9
- from .other_classes import (
10
- DotDict,
11
- )
12
- from .constants import (
13
- ctrl_key,
14
- rc_binding,
15
- )
16
- from .functions import (
17
- recursive_bind,
18
- )
7
+ from .constants import ctrl_key, rc_binding
8
+ from .functions import recursive_bind
9
+ from .other_classes import DotDict
19
10
 
20
11
 
21
12
  class FindWindowTkText(tk.Text):
tksheet/functions.py CHANGED
@@ -5,41 +5,166 @@ import io
5
5
  import pickle
6
6
  import re
7
7
  import tkinter as tk
8
- from bisect import (
9
- bisect_left,
10
- )
8
+ from bisect import bisect_left
11
9
  from collections import deque
12
- from collections.abc import (
13
- Callable,
14
- Generator,
15
- Hashable,
16
- Iterable,
17
- Iterator,
18
- Sequence,
19
- )
10
+ from collections.abc import Callable, Generator, Hashable, Iterable, Iterator, Sequence
20
11
  from itertools import islice, repeat
21
12
  from typing import Literal
22
13
 
23
14
  from .colors import color_map
24
- from .constants import (
25
- symbols_set,
26
- )
27
- from .formatters import (
28
- to_bool,
29
- )
30
- from .other_classes import (
31
- Box_nt,
32
- DotDict,
33
- EventDataDict,
34
- Highlight,
35
- Loc,
36
- Span,
37
- )
38
- from .types import (
39
- AnyIter,
40
- )
15
+ from .constants import align_value_error, symbols_set
16
+ from .formatters import to_bool
17
+ from .other_classes import Box_nt, DotDict, EventDataDict, Highlight, Loc, Span
18
+ from .tksheet_types import AnyIter
41
19
 
42
20
  unpickle_obj = pickle.loads
21
+ lines_re = re.compile(r"[^\n]+")
22
+
23
+
24
+ def wrap_text(
25
+ text: str,
26
+ max_width: int,
27
+ max_lines: int,
28
+ char_width_fn: Callable,
29
+ widths: dict[str, int],
30
+ wrap: Literal["", "c", "w"] = "",
31
+ start_line: int = 0,
32
+ ) -> Generator[str]:
33
+ lines = (match.group() for match in lines_re.finditer(text))
34
+ current_line = []
35
+ total_lines = 0
36
+ line_width = 0
37
+
38
+ if not wrap:
39
+ for line in lines:
40
+ line_width = 0
41
+ current_line = []
42
+ for char in line:
43
+ char_width = widths.get(char, char_width_fn(char))
44
+ line_width += char_width
45
+ if line_width >= max_width:
46
+ break
47
+ current_line.append(char)
48
+
49
+ if total_lines >= start_line:
50
+ yield "".join(current_line)
51
+
52
+ # Count the line whether it's empty or not
53
+ total_lines += 1
54
+ if total_lines >= max_lines:
55
+ return
56
+
57
+ elif wrap == "c":
58
+ for line in lines:
59
+ for char in line:
60
+ char_width = widths.get(char, char_width_fn(char))
61
+
62
+ # adding char to line would result in wrap
63
+ if line_width + char_width >= max_width:
64
+ if total_lines >= start_line:
65
+ yield "".join(current_line)
66
+
67
+ total_lines += 1
68
+ if total_lines >= max_lines:
69
+ return
70
+ current_line = []
71
+ line_width = 0
72
+
73
+ if char_width <= max_width:
74
+ current_line.append(char)
75
+ line_width = char_width
76
+ # adding char to line is okay
77
+ else:
78
+ current_line.append(char)
79
+ line_width += char_width
80
+
81
+ if total_lines >= start_line:
82
+ yield "".join(current_line)
83
+
84
+ total_lines += 1
85
+ if total_lines >= max_lines:
86
+ return
87
+ current_line = [] # Reset for next line
88
+ line_width = 0
89
+
90
+ elif wrap == "w":
91
+ space_width = widths.get(" ", char_width_fn(" "))
92
+
93
+ for line in lines:
94
+ words = line.split()
95
+ for i, word in enumerate(words):
96
+ # if we're going to next word and
97
+ # if a space fits on the end of the current line we add one
98
+ if i and line_width + space_width < max_width:
99
+ current_line.append(" ")
100
+ line_width += space_width
101
+
102
+ # check if word will fit
103
+ word_width = 0
104
+ word_char_widths = []
105
+ for char in word:
106
+ word_char_widths.append((w := widths.get(char, char_width_fn(char))))
107
+ word_width += w
108
+
109
+ # we only wrap by character if the whole word alone wont fit max width
110
+ # word won't fit at all we resort to char wrapping it
111
+ if word_width >= max_width:
112
+ # yield current line before char wrapping word
113
+ if current_line:
114
+ if total_lines >= start_line:
115
+ yield "".join(current_line)
116
+
117
+ total_lines += 1
118
+ if total_lines >= max_lines:
119
+ return
120
+ current_line = []
121
+ line_width = 0
122
+
123
+ for char, w in zip(word, word_char_widths):
124
+ # adding char to line would result in wrap
125
+ if line_width + w >= max_width:
126
+ if total_lines >= start_line:
127
+ yield "".join(current_line)
128
+
129
+ total_lines += 1
130
+ if total_lines >= max_lines:
131
+ return
132
+ current_line = []
133
+ line_width = 0
134
+
135
+ if w <= max_width:
136
+ current_line.append(char)
137
+ line_width = w
138
+ # adding char to line is okay
139
+ else:
140
+ current_line.append(char)
141
+ line_width += w
142
+
143
+ # word won't fit on current line but will fit on a newline
144
+ elif line_width + word_width >= max_width:
145
+ if total_lines >= start_line:
146
+ yield "".join(current_line)
147
+
148
+ total_lines += 1
149
+ if total_lines >= max_lines:
150
+ return
151
+ current_line = [word]
152
+ line_width = word_width
153
+
154
+ # word will fit we put it on the current line
155
+ else:
156
+ current_line.append(word)
157
+ line_width += word_width
158
+
159
+ if total_lines >= start_line:
160
+ yield "".join(current_line)
161
+
162
+ total_lines += 1
163
+ if total_lines >= max_lines:
164
+ return
165
+
166
+ current_line = [] # Reset for next line
167
+ line_width = 0
43
168
 
44
169
 
45
170
  def get_csv_str_dialect(s: str, delimiters: str) -> csv.Dialect:
@@ -183,6 +308,8 @@ def event_dict(
183
308
  # resized_header: None, dict] = None,
184
309
  being_selected: None | tuple = None,
185
310
  named_spans: None | dict = None,
311
+ sheet_state: None | dict = None,
312
+ treeview: None | dict = None,
186
313
  **kwargs,
187
314
  ) -> EventDataDict:
188
315
  return EventDataDict(
@@ -208,8 +335,6 @@ def event_dict(
208
335
  index=DotDict(),
209
336
  column_widths=DotDict(),
210
337
  row_heights=DotDict(),
211
- displayed_rows=None,
212
- displayed_columns=None,
213
338
  ),
214
339
  named_spans=DotDict() if named_spans is None else named_spans,
215
340
  options=DotDict(),
@@ -231,6 +356,12 @@ def event_dict(
231
356
  # "index": DotDict() if resized_index is None else resized_index,
232
357
  ),
233
358
  widget=widget,
359
+ sheet_state=DotDict() if sheet_state is None else sheet_state,
360
+ treeview=DotDict(
361
+ nodes={},
362
+ )
363
+ if treeview is None
364
+ else treeview,
234
365
  )
235
366
 
236
367
 
@@ -258,6 +389,12 @@ def b_index(sorted_seq: Sequence[int], num_to_index: int) -> int:
258
389
  return idx
259
390
 
260
391
 
392
+ def try_b_index(sorted_seq: Sequence[int], num_to_index: int) -> int | None:
393
+ if (idx := bisect_left(sorted_seq, num_to_index)) == len(sorted_seq) or sorted_seq[idx] != num_to_index:
394
+ return None
395
+ return idx
396
+
397
+
261
398
  def bisect_in(sorted_seq: Sequence[int], num: int) -> bool:
262
399
  """
263
400
  Faster than 'num in sorted_seq'
@@ -268,6 +405,18 @@ def bisect_in(sorted_seq: Sequence[int], num: int) -> bool:
268
405
  return False
269
406
 
270
407
 
408
+ def push_n(num: int, sorted_seq: Sequence[int]) -> int:
409
+ if num < sorted_seq[0]:
410
+ return num
411
+ else:
412
+ for e in sorted_seq:
413
+ if num >= e:
414
+ num += 1
415
+ else:
416
+ return num
417
+ return num
418
+
419
+
271
420
  def get_dropdown_kwargs(
272
421
  values: list = [],
273
422
  set_value: object = None,
@@ -638,6 +787,18 @@ def insert_items(
638
787
  return seq
639
788
 
640
789
 
790
+ def del_placeholder_dict_key(
791
+ d: dict[Hashable, object],
792
+ k: Hashable,
793
+ v: object,
794
+ p: tuple = tuple(),
795
+ ) -> dict[Hashable, object]:
796
+ if p in d:
797
+ del d[p]
798
+ d[k] = v
799
+ return d
800
+
801
+
641
802
  def data_to_displayed_idxs(
642
803
  to_convert: list[int],
643
804
  displayed: list[int],
@@ -1412,15 +1573,15 @@ def convert_align(align: str | None) -> str | None:
1412
1573
  a = align.lower()
1413
1574
  if a == "global":
1414
1575
  return None
1415
- elif a in ("c", "center", "centre"):
1416
- return "center"
1417
- elif a in ("w", "west", "left"):
1418
- return "w"
1419
- elif a in ("e", "east", "right"):
1420
- return "e"
1576
+ elif a in ("c", "center", "centre", "n"):
1577
+ return "n"
1578
+ elif a in ("w", "west", "left", "nw"):
1579
+ return "nw"
1580
+ elif a in ("e", "east", "right", "ne"):
1581
+ return "ne"
1421
1582
  elif align is None:
1422
1583
  return None
1423
- raise ValueError("Align must be one of the following values: c, center, w, west, left, e, east, right")
1584
+ raise ValueError(align_value_error)
1424
1585
 
1425
1586
 
1426
1587
  def set_align(