tksheet 7.4.11__tar.gz → 7.4.13__tar.gz

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.
Files changed (26) hide show
  1. {tksheet-7.4.11/tksheet.egg-info → tksheet-7.4.13}/PKG-INFO +7 -7
  2. {tksheet-7.4.11 → tksheet-7.4.13}/README.md +6 -6
  3. {tksheet-7.4.11 → tksheet-7.4.13}/pyproject.toml +1 -1
  4. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/__init__.py +1 -1
  5. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/column_headers.py +44 -65
  6. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/functions.py +109 -38
  7. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/main_table.py +325 -316
  8. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/other_classes.py +4 -2
  9. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/row_index.py +177 -167
  10. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/sheet.py +16 -10
  11. {tksheet-7.4.11 → tksheet-7.4.13/tksheet.egg-info}/PKG-INFO +7 -7
  12. {tksheet-7.4.11 → tksheet-7.4.13}/LICENSE.txt +0 -0
  13. {tksheet-7.4.11 → tksheet-7.4.13}/setup.cfg +0 -0
  14. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/colors.py +0 -0
  15. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/constants.py +0 -0
  16. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/find_window.py +0 -0
  17. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/formatters.py +0 -0
  18. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/sheet_options.py +0 -0
  19. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/sorting.py +0 -0
  20. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/text_editor.py +0 -0
  21. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/themes.py +0 -0
  22. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/tksheet_types.py +0 -0
  23. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet/top_left_rectangle.py +0 -0
  24. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet.egg-info/SOURCES.txt +0 -0
  25. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet.egg-info/dependency_links.txt +0 -0
  26. {tksheet-7.4.11 → tksheet-7.4.13}/tksheet.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tksheet
3
- Version: 7.4.11
3
+ Version: 7.4.13
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
@@ -63,23 +63,23 @@ License-File: LICENSE.txt
63
63
  <tbody>
64
64
  <tr>
65
65
  <td style="color: LightCoral">Versions 6.x.x &#8594;</td>
66
- <td><a href="https://github.com/ragardner/tksheet/wiki/Version-6">Documentation Wiki</a></td>
66
+ <td><a href="https://github.com/ragardner/tksheet/wiki/Version-6" target="_blank">Documentation</a></td>
67
67
  </tr>
68
68
  <tr>
69
69
  <td style="color: lightgreen">Versions 7.x.x &#8594;</td>
70
- <td><a href="https://github.com/ragardner/tksheet/wiki/Version-7">Documentation Wiki</a></td>
70
+ <td><a href="https://ragardner.github.io/tksheet/DOCUMENTATION.html" target="_blank">Documentation</a></td>
71
71
  </tr>
72
72
  <tr>
73
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/blob/master/docs/CHANGELOG.md">Changelog</a></td>
73
+ <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/blob/master/docs/CHANGELOG.md" target="_blank">Changelog</a></td>
74
74
  </tr>
75
75
  <tr>
76
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#asking-questions">Questions</a></td>
76
+ <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#asking-questions" target="_blank">Questions</a></td>
77
77
  </tr>
78
78
  <tr>
79
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#issues">Issues</a></td>
79
+ <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#issues" target="_blank">Issues</a></td>
80
80
  </tr>
81
81
  <tr>
82
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#enhancements-or-suggestions">Suggestions and Contributors</a></td>
82
+ <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>
83
83
  </tr>
84
84
  </tbody>
85
85
  </table>
@@ -18,23 +18,23 @@
18
18
  <tbody>
19
19
  <tr>
20
20
  <td style="color: LightCoral">Versions 6.x.x &#8594;</td>
21
- <td><a href="https://github.com/ragardner/tksheet/wiki/Version-6">Documentation Wiki</a></td>
21
+ <td><a href="https://github.com/ragardner/tksheet/wiki/Version-6" target="_blank">Documentation</a></td>
22
22
  </tr>
23
23
  <tr>
24
24
  <td style="color: lightgreen">Versions 7.x.x &#8594;</td>
25
- <td><a href="https://github.com/ragardner/tksheet/wiki/Version-7">Documentation Wiki</a></td>
25
+ <td><a href="https://ragardner.github.io/tksheet/DOCUMENTATION.html" target="_blank">Documentation</a></td>
26
26
  </tr>
27
27
  <tr>
28
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/blob/master/docs/CHANGELOG.md">Changelog</a></td>
28
+ <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/blob/master/docs/CHANGELOG.md" target="_blank">Changelog</a></td>
29
29
  </tr>
30
30
  <tr>
31
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#asking-questions">Questions</a></td>
31
+ <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#asking-questions" target="_blank">Questions</a></td>
32
32
  </tr>
33
33
  <tr>
34
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#issues">Issues</a></td>
34
+ <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#issues" target="_blank">Issues</a></td>
35
35
  </tr>
36
36
  <tr>
37
- <td align="right" colspan="2"><a href="https://github.com/ragardner/tksheet/wiki/Version-7#enhancements-or-suggestions">Suggestions and Contributors</a></td>
37
+ <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>
38
38
  </tr>
39
39
  </tbody>
40
40
  </table>
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
  name = "tksheet"
7
7
  description = "Tkinter table / sheet and treeview widget"
8
8
  readme = "README.md"
9
- version = "7.4.11"
9
+ version = "7.4.13"
10
10
  authors = [{ name = "ragardner", email = "github@ragardner.simplelogin.com" }]
11
11
  requires-python = ">=3.8"
12
12
  license = {file = "LICENSE.txt"}
@@ -4,7 +4,7 @@
4
4
  tksheet - A Python tkinter table widget
5
5
  """
6
6
 
7
- __version__ = "7.4.11"
7
+ __version__ = "7.4.13"
8
8
 
9
9
  from .colors import (
10
10
  color_map,
@@ -5,7 +5,7 @@ from collections import defaultdict
5
5
  from collections.abc import Callable, Hashable, Iterator, Sequence
6
6
  from functools import partial
7
7
  from itertools import cycle, islice, repeat
8
- from math import ceil, floor
8
+ from math import ceil
9
9
  from operator import itemgetter
10
10
  from typing import Any, Literal
11
11
 
@@ -741,7 +741,7 @@ class ColumnHeaders(tk.Canvas):
741
741
  if size < self.ops.min_column_width:
742
742
  new_col_pos = ceil(self.MT.col_positions[self.rsz_w - 1] + self.ops.min_column_width)
743
743
  elif size > self.ops.max_column_width:
744
- new_col_pos = floor(self.MT.col_positions[self.rsz_w - 1] + self.ops.max_column_width)
744
+ new_col_pos = int(self.MT.col_positions[self.rsz_w - 1] + self.ops.max_column_width)
745
745
  increment = new_col_pos - self.MT.col_positions[self.rsz_w]
746
746
  self.MT.col_positions[self.rsz_w + 1 :] = [
747
747
  e + increment for e in islice(self.MT.col_positions, self.rsz_w + 1, None)
@@ -1058,44 +1058,6 @@ class ColumnHeaders(tk.Canvas):
1058
1058
  self.MT.run_selection_binding("columns")
1059
1059
  return fill_iid
1060
1060
 
1061
- def display_box(
1062
- self,
1063
- x1: int,
1064
- y1: int,
1065
- x2: int,
1066
- y2: int,
1067
- fill: str,
1068
- outline: str,
1069
- state: str,
1070
- tags: str | tuple[str],
1071
- iid: None | int = None,
1072
- ) -> int:
1073
- coords = rounded_box_coords(
1074
- x1,
1075
- y1,
1076
- x2,
1077
- y2,
1078
- radius=5 if self.ops.rounded_boxes else 0,
1079
- )
1080
- if isinstance(iid, int):
1081
- self.coords(iid, coords)
1082
- self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags)
1083
- else:
1084
- if self.hidd_boxes:
1085
- iid = self.hidd_boxes.pop()
1086
- self.coords(iid, coords)
1087
- self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags)
1088
- else:
1089
- iid = self.create_polygon(coords, fill=fill, outline=outline, state=state, tags=tags, smooth=True)
1090
- self.disp_boxes.add(iid)
1091
- return iid
1092
-
1093
- def hide_box(self, item: int) -> None:
1094
- if isinstance(item, int):
1095
- self.disp_boxes.discard(item)
1096
- self.hidd_boxes.add(item)
1097
- self.itemconfig(item, state="hidden")
1098
-
1099
1061
  def get_cell_dimensions(self, datacn: int) -> tuple[int, int]:
1100
1062
  txt = self.cell_str(datacn, fix=False)
1101
1063
  if txt:
@@ -1279,6 +1241,7 @@ class ColumnHeaders(tk.Canvas):
1279
1241
  sel_cols_bg: str,
1280
1242
  selections: dict,
1281
1243
  datacn: int,
1244
+ has_dd: bool,
1282
1245
  ) -> tuple[str, bool]:
1283
1246
  redrawn = False
1284
1247
  kwargs = self.get_cell_kwargs(datacn, key="highlight")
@@ -1319,18 +1282,32 @@ class ColumnHeaders(tk.Canvas):
1319
1282
  sc,
1320
1283
  self.current_height - 1,
1321
1284
  fill=fill,
1322
- outline=(
1323
- self.ops.header_fg
1324
- if self.get_cell_kwargs(datacn, key="dropdown") and self.ops.show_dropdown_borders
1325
- else ""
1326
- ),
1285
+ outline=self.ops.header_fg if has_dd and self.ops.show_dropdown_borders else "",
1327
1286
  tag="hi",
1328
1287
  )
1329
1288
  elif not kwargs:
1330
1289
  if "columns" in selections and c in selections["columns"]:
1331
1290
  txtfg = self.ops.header_selected_columns_fg
1291
+ redrawn = self.redraw_highlight(
1292
+ fc + 1,
1293
+ 0,
1294
+ sc,
1295
+ self.current_height - 1,
1296
+ fill=self.ops.header_selected_columns_bg,
1297
+ outline=self.ops.header_fg if has_dd and self.ops.show_dropdown_borders else "",
1298
+ tag="hi",
1299
+ )
1332
1300
  elif "cells" in selections and c in selections["cells"]:
1333
1301
  txtfg = self.ops.header_selected_cells_fg
1302
+ redrawn = self.redraw_highlight(
1303
+ fc + 1,
1304
+ 0,
1305
+ sc,
1306
+ self.current_height - 1,
1307
+ fill=self.ops.header_selected_cells_bg,
1308
+ outline=self.ops.header_fg if has_dd and self.ops.show_dropdown_borders else "",
1309
+ tag="hi",
1310
+ )
1334
1311
  else:
1335
1312
  txtfg = self.ops.header_fg
1336
1313
  return txtfg, redrawn
@@ -1396,7 +1373,7 @@ class ColumnHeaders(tk.Canvas):
1396
1373
  if draw_arrow:
1397
1374
  mod = (self.MT.header_txt_height - 1) if self.MT.header_txt_height % 2 else self.MT.header_txt_height
1398
1375
  small_mod = int(mod / 5)
1399
- mid_y = floor(self.MT.min_header_height / 2)
1376
+ mid_y = int(self.MT.min_header_height / 2)
1400
1377
  if open_:
1401
1378
  # up arrow
1402
1379
  points = (
@@ -1559,6 +1536,7 @@ class ColumnHeaders(tk.Canvas):
1559
1536
  cleftgridln = self.MT.col_positions[c]
1560
1537
  crightgridln = self.MT.col_positions[c + 1]
1561
1538
  datacn = c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
1539
+ kwargs = self.get_cell_kwargs(datacn, key="dropdown")
1562
1540
  fill, dd_drawn = self.redraw_highlight_get_text_fg(
1563
1541
  fc=cleftgridln,
1564
1542
  sc=crightgridln,
@@ -1567,19 +1545,20 @@ class ColumnHeaders(tk.Canvas):
1567
1545
  sel_cols_bg=sel_cols_bg,
1568
1546
  selections=selections,
1569
1547
  datacn=datacn,
1548
+ has_dd=bool(kwargs),
1570
1549
  )
1571
1550
  if datacn in self.cell_options and "align" in self.cell_options[datacn]:
1572
1551
  align = self.cell_options[datacn]["align"]
1573
1552
  else:
1574
1553
  align = self.align
1575
- if kwargs := self.get_cell_kwargs(datacn, key="dropdown"):
1576
- max_width = crightgridln - cleftgridln - txt_h - 2
1577
- if align.endswith("w"):
1554
+ if kwargs:
1555
+ max_width = crightgridln - cleftgridln - txt_h - 5
1556
+ if align[-1] == "w":
1578
1557
  draw_x = cleftgridln + 2
1579
- elif align.endswith("e"):
1558
+ elif align[-1] == "e":
1580
1559
  draw_x = crightgridln - 5 - txt_h
1581
- elif align.endswith("n"):
1582
- draw_x = cleftgridln + ceil((crightgridln - cleftgridln - txt_h) / 2)
1560
+ elif align[-1] == "n":
1561
+ draw_x = cleftgridln + (crightgridln - cleftgridln - txt_h) / 2
1583
1562
  self.redraw_dropdown(
1584
1563
  cleftgridln,
1585
1564
  0,
@@ -1594,18 +1573,18 @@ class ColumnHeaders(tk.Canvas):
1594
1573
  )
1595
1574
  else:
1596
1575
  max_width = crightgridln - cleftgridln - 2
1597
- if align.endswith("w"):
1576
+ if align[-1] == "w":
1598
1577
  draw_x = cleftgridln + 2
1599
- elif align.endswith("e"):
1578
+ elif align[-1] == "e":
1600
1579
  draw_x = crightgridln - 2
1601
- elif align.endswith("n"):
1602
- draw_x = cleftgridln + floor((crightgridln - cleftgridln) / 2)
1580
+ elif align[-1] == "n":
1581
+ draw_x = cleftgridln + (crightgridln - cleftgridln) / 2
1603
1582
  if (kwargs := self.get_cell_kwargs(datacn, key="checkbox")) and max_width > txt_h + 1:
1604
1583
  box_w = txt_h + 1
1605
- if align.endswith("w"):
1584
+ if align[-1] == "w":
1606
1585
  draw_x += box_w + 3
1607
- elif align.endswith("n"):
1608
- draw_x += ceil(box_w / 2) + 1
1586
+ elif align[-1] == "n":
1587
+ draw_x += box_w / 2 + 1
1609
1588
  max_width -= box_w + 4
1610
1589
  try:
1611
1590
  draw_check = (
@@ -1627,9 +1606,9 @@ class ColumnHeaders(tk.Canvas):
1627
1606
  )
1628
1607
  if (
1629
1608
  max_width < self.MT.header_txt_width
1630
- or (align.endswith("w") and draw_x > scrollpos_right)
1631
- or (align.endswith("e") and cleftgridln + 5 > scrollpos_right)
1632
- or (align.endswith("n") and cleftgridln + 5 > scrollpos_right)
1609
+ or (align[-1] == "w" and draw_x > scrollpos_right)
1610
+ or (align[-1] == "e" and cleftgridln + 5 > scrollpos_right)
1611
+ or (align[-1] == "n" and cleftgridln + 5 > scrollpos_right)
1633
1612
  ):
1634
1613
  continue
1635
1614
  text = self.cell_str(datacn, fix=False)
@@ -1664,7 +1643,6 @@ class ColumnHeaders(tk.Canvas):
1664
1643
  anchor=align,
1665
1644
  state="normal",
1666
1645
  )
1667
- self.tag_raise(iid)
1668
1646
  else:
1669
1647
  iid = self.create_text(
1670
1648
  draw_x,
@@ -1709,6 +1687,7 @@ class ColumnHeaders(tk.Canvas):
1709
1687
  if showing:
1710
1688
  self.itemconfig(iid, state="hidden")
1711
1689
  dct[iid] = False
1690
+ self.tag_raise("t")
1712
1691
  if self.disp_resize_lines:
1713
1692
  self.tag_raise("rw")
1714
1693
  return True
@@ -2314,8 +2293,8 @@ class ColumnHeaders(tk.Canvas):
2314
2293
  kwargs = self.get_cell_kwargs(datacn, key=None, cell=c_ops)
2315
2294
  if "checkbox" in kwargs:
2316
2295
  return False
2317
- elif (kwargs := kwargs.get("dropdown", {})) and kwargs["validate_input"] and kwargs["values"]:
2318
- return kwargs["values"][0]
2296
+ elif "dropdown" in kwargs and kwargs["dropdown"]["validate_input"] and kwargs["dropdown"]["values"]:
2297
+ return kwargs["dropdown"]["values"][0]
2319
2298
  else:
2320
2299
  return ""
2321
2300
 
@@ -9,7 +9,7 @@ from bisect import bisect_left
9
9
  from collections import deque
10
10
  from collections.abc import Callable, Generator, Hashable, Iterable, Iterator, Sequence
11
11
  from difflib import SequenceMatcher
12
- from itertools import islice, repeat
12
+ from itertools import chain, islice, repeat
13
13
  from typing import Any, Literal
14
14
 
15
15
  from .colors import color_map
@@ -31,34 +31,16 @@ def wrap_text(
31
31
  wrap: Literal["", "c", "w"] = "",
32
32
  start_line: int = 0,
33
33
  ) -> Generator[str]:
34
- lines = (match.group() for match in lines_re.finditer(text))
35
- current_line = []
36
34
  total_lines = 0
37
35
  line_width = 0
38
-
39
- if not wrap:
40
- for line in lines:
41
- line_width = 0
42
- current_line = []
43
- for char in line:
44
- char_width = widths.get(char, char_width_fn(char))
45
- line_width += char_width
46
- if line_width >= max_width:
47
- break
48
- current_line.append(char)
49
-
50
- if total_lines >= start_line:
51
- yield "".join(current_line)
52
-
53
- # Count the line whether it's empty or not
54
- total_lines += 1
55
- if total_lines >= max_lines:
56
- return
57
-
58
- elif wrap == "c":
59
- for line in lines:
60
- for char in line:
61
- char_width = widths.get(char, char_width_fn(char))
36
+ if wrap == "c":
37
+ current_line = []
38
+ for match in lines_re.finditer(text):
39
+ for char in match.group():
40
+ try:
41
+ char_width = widths[char]
42
+ except KeyError:
43
+ char_width = char_width_fn(char)
62
44
 
63
45
  # adding char to line would result in wrap
64
46
  if line_width + char_width >= max_width:
@@ -89,11 +71,14 @@ def wrap_text(
89
71
  line_width = 0
90
72
 
91
73
  elif wrap == "w":
92
- space_width = widths.get(" ", char_width_fn(" "))
74
+ try:
75
+ space_width = widths[" "]
76
+ except KeyError:
77
+ space_width = char_width_fn(" ")
78
+ current_line = []
93
79
 
94
- for line in lines:
95
- words = line.split()
96
- for i, word in enumerate(words):
80
+ for match in lines_re.finditer(text):
81
+ for i, word in enumerate(match.group().split()):
97
82
  # if we're going to next word and
98
83
  # if a space fits on the end of the current line we add one
99
84
  if i and line_width + space_width < max_width:
@@ -104,8 +89,12 @@ def wrap_text(
104
89
  word_width = 0
105
90
  word_char_widths = []
106
91
  for char in word:
107
- word_char_widths.append((w := widths.get(char, char_width_fn(char))))
108
- word_width += w
92
+ try:
93
+ char_width = widths[char]
94
+ except KeyError:
95
+ char_width = char_width_fn(char)
96
+ word_char_widths.append(char_width)
97
+ word_width += char_width
109
98
 
110
99
  # we only wrap by character if the whole word alone wont fit max width
111
100
  # word won't fit at all we resort to char wrapping it
@@ -167,6 +156,28 @@ def wrap_text(
167
156
  current_line = [] # Reset for next line
168
157
  line_width = 0
169
158
 
159
+ else:
160
+ for match in lines_re.finditer(text):
161
+ line_width = 0
162
+ current_line = []
163
+ for char in match.group():
164
+ try:
165
+ char_width = widths[char]
166
+ except KeyError:
167
+ char_width = char_width_fn(char)
168
+ line_width += char_width
169
+ if line_width >= max_width:
170
+ break
171
+ current_line.append(char)
172
+
173
+ if total_lines >= start_line:
174
+ yield "".join(current_line)
175
+
176
+ # Count the line whether it's empty or not
177
+ total_lines += 1
178
+ if total_lines >= max_lines:
179
+ return
180
+
170
181
 
171
182
  def get_csv_str_dialect(s: str, delimiters: str) -> csv.Dialect:
172
183
  if len(s) > 6000:
@@ -782,6 +793,11 @@ def move_elements_by_mapping_gen(
782
793
  return (seq[old_idxs[i]] if i in old_idxs else next(remaining_values) for i in range(len(seq)))
783
794
 
784
795
 
796
+ def move_fast(seq: list[Any], new_idxs: dict[int, int], old_idxs: dict[int, int]) -> list[Any]:
797
+ remaining_values = (e for i, e in enumerate(seq) if i not in new_idxs)
798
+ return [seq[old_idxs[i]] if i in old_idxs else next(remaining_values) for i in range(len(seq))]
799
+
800
+
785
801
  def move_elements_to(
786
802
  seq: list[Any],
787
803
  move_to: int,
@@ -808,10 +824,17 @@ def get_new_indexes(
808
824
  returns {old idx: new idx, ...}
809
825
  """
810
826
  offset = sum(1 for i in to_move if i < move_to)
811
- new_idxs = dict(zip(to_move, range(move_to - offset, move_to - offset + len(to_move))))
812
- if get_inverse:
813
- return new_idxs, dict(zip(new_idxs.values(), new_idxs))
814
- return new_idxs
827
+ correct_move_to = move_to - offset
828
+ if not get_inverse:
829
+ return {elem: correct_move_to + i for i, elem in enumerate(to_move)}
830
+ else:
831
+ new_idxs = {}
832
+ old_idxs = {}
833
+ for i, elem in enumerate(to_move):
834
+ value = correct_move_to + i
835
+ new_idxs[elem] = value
836
+ old_idxs[value] = elem
837
+ return new_idxs, old_idxs
815
838
 
816
839
 
817
840
  def insert_items(
@@ -822,7 +845,7 @@ def insert_items(
822
845
  """
823
846
  seq: list[Any]
824
847
  to_insert: keys are ints sorted, representing list indexes to insert items.
825
- Values are any, e.g. {1: 200, 0: 200}
848
+ Values are any, e.g. {0: 200, 1: 200}
826
849
  """
827
850
  if to_insert:
828
851
  if seq_len_func and next(reversed(to_insert)) >= len(seq) + len(to_insert):
@@ -1684,3 +1707,51 @@ def pop_positions(
1684
1707
  save_to[to_pop[i]] = pos
1685
1708
  else:
1686
1709
  yield pos
1710
+
1711
+
1712
+ def get_horizontal_gridline_points(
1713
+ left: float,
1714
+ stop: float,
1715
+ positions: list[float],
1716
+ start: int,
1717
+ end: int,
1718
+ ) -> list[int | float]:
1719
+ return list(
1720
+ chain.from_iterable(
1721
+ (
1722
+ left - 1,
1723
+ positions[r],
1724
+ stop,
1725
+ positions[r],
1726
+ left - 1,
1727
+ positions[r],
1728
+ left - 1,
1729
+ positions[r + 1] if len(positions) - 1 > r else positions[r],
1730
+ )
1731
+ for r in range(start, end)
1732
+ )
1733
+ )
1734
+
1735
+
1736
+ def get_vertical_gridline_points(
1737
+ top: float,
1738
+ stop: float,
1739
+ positions: list[float],
1740
+ start: int,
1741
+ end: int,
1742
+ ) -> list[float]:
1743
+ return list(
1744
+ chain.from_iterable(
1745
+ (
1746
+ positions[c],
1747
+ top - 1,
1748
+ positions[c],
1749
+ stop,
1750
+ positions[c],
1751
+ top - 1,
1752
+ positions[c + 1] if len(positions) - 1 > c else positions[c],
1753
+ top - 1,
1754
+ )
1755
+ for c in range(start, end)
1756
+ )
1757
+ )