tksheet 7.3.0__py3-none-any.whl → 7.3.2__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/main_table.py CHANGED
@@ -15,7 +15,6 @@ from collections.abc import (
15
15
  Callable,
16
16
  Generator,
17
17
  Hashable,
18
- Iterator,
19
18
  Sequence,
20
19
  )
21
20
  from functools import (
@@ -40,6 +39,22 @@ from typing import Literal
40
39
  from .colors import (
41
40
  color_map,
42
41
  )
42
+ from .constants import (
43
+ USER_OS,
44
+ bind_add_columns,
45
+ bind_add_rows,
46
+ bind_del_columns,
47
+ bind_del_rows,
48
+ ctrl_key,
49
+ rc_binding,
50
+ text_editor_close_bindings,
51
+ text_editor_newline_bindings,
52
+ text_editor_to_unbind,
53
+ val_modifying_options,
54
+ )
55
+ from .find_window import (
56
+ FindWindow,
57
+ )
43
58
  from .formatters import (
44
59
  data_to_str,
45
60
  format_data,
@@ -51,6 +66,7 @@ from .formatters import (
51
66
  from .functions import (
52
67
  add_to_displayed,
53
68
  b_index,
69
+ bisect_in,
54
70
  box_is_single_cell,
55
71
  cell_right_within_box,
56
72
  color_tup,
@@ -59,6 +75,8 @@ from .functions import (
59
75
  diff_list,
60
76
  down_cell_within_box,
61
77
  event_dict,
78
+ event_has_char_key,
79
+ event_opens_dropdown_or_checkbox,
62
80
  float_to_int,
63
81
  gen_formatted,
64
82
  get_data_from_clipboard,
@@ -87,6 +105,7 @@ from .other_classes import (
87
105
  Box_t,
88
106
  DotDict,
89
107
  DropdownStorage,
108
+ EditorStorageBase,
90
109
  EventDataDict,
91
110
  FontTuple,
92
111
  Highlight,
@@ -99,19 +118,8 @@ from .other_classes import (
99
118
  from .text_editor import (
100
119
  TextEditor,
101
120
  )
102
- from .vars import (
103
- USER_OS,
104
- bind_add_columns,
105
- bind_add_rows,
106
- bind_del_columns,
107
- bind_del_rows,
108
- ctrl_key,
109
- rc_binding,
110
- symbols_set,
111
- text_editor_close_bindings,
112
- text_editor_newline_bindings,
113
- text_editor_to_unbind,
114
- val_modifying_options,
121
+ from .types import (
122
+ AnyIter,
115
123
  )
116
124
 
117
125
 
@@ -138,6 +146,7 @@ class MainTable(tk.Canvas):
138
146
  self.synced_scrolls = set()
139
147
  self.dropdown = DropdownStorage()
140
148
  self.text_editor = TextEditorStorage()
149
+ self.find_window = EditorStorageBase()
141
150
  self.event_linker = {
142
151
  "<<Copy>>": self.ctrl_c,
143
152
  "<<Cut>>": self.ctrl_x,
@@ -246,6 +255,7 @@ class MainTable(tk.Canvas):
246
255
  self.drag_selection_enabled = False
247
256
  self.select_all_enabled = False
248
257
  self.undo_enabled = False
258
+ self.find_enabled = False
249
259
  self.cut_enabled = False
250
260
  self.copy_enabled = False
251
261
  self.paste_enabled = False
@@ -405,7 +415,9 @@ class MainTable(tk.Canvas):
405
415
  ("<Control-MouseWheel>", self.ctrl_mousewheel),
406
416
  ("<Control-plus>", self.zoom_in),
407
417
  ("<Control-equal>", self.zoom_in),
418
+ ("<Meta-Command-equal>", self.zoom_in),
408
419
  ("<Control-minus>", self.zoom_out),
420
+ ("<Meta-Command-minus>", self.zoom_out),
409
421
  )
410
422
  mt_ri_canvas_linux_bindings = {
411
423
  ("<Button-4>", self.mousewheel),
@@ -472,6 +484,250 @@ class MainTable(tk.Canvas):
472
484
  if delete_on_timer:
473
485
  self.after(1500, self.delete_ctrl_outlines)
474
486
 
487
+ def escape(self, event: tk.Misc | None) -> None:
488
+ if self.find_window.open:
489
+ self.close_find_window()
490
+ else:
491
+ self.deselect()
492
+
493
+ def get_find_window_dimensions_coords(self, w_width: int) -> tuple[int, int, int, int]:
494
+ width = min(self.get_txt_w("X" * 23), w_width - 7)
495
+ # w, h, x, y
496
+ return width, self.min_row_height, self.canvasx(max(0, w_width - width - 7)), self.canvasy(7)
497
+
498
+ def open_find_window(
499
+ self,
500
+ event: tk.Misc | None = None,
501
+ focus: bool = True,
502
+ ) -> Literal["break"]:
503
+ if self.find_window.open:
504
+ self.close_find_window()
505
+ return "break"
506
+ width, height, x, y = self.get_find_window_dimensions_coords(w_width=self.winfo_width())
507
+ if not self.find_window.window:
508
+ self.find_window.window = FindWindow(
509
+ self,
510
+ find_prev_func=self.find_previous,
511
+ find_next_func=self.find_next,
512
+ close_func=self.close_find_window,
513
+ )
514
+ self.find_window.canvas_id = self.create_window((x, y), window=self.find_window.window, anchor="nw")
515
+ for b in chain(self.PAR.ops.escape_bindings, self.PAR.ops.find_bindings):
516
+ self.find_window.tktext.bind(b, self.close_find_window)
517
+ for b in chain(self.PAR.ops.find_next_bindings, ("<Return>", "<KP_Enter>")):
518
+ self.find_window.tktext.bind(b, self.find_next)
519
+ for b in self.PAR.ops.find_previous_bindings:
520
+ self.find_window.tktext.bind(b, self.find_previous)
521
+ else:
522
+ self.coords(self.find_window.canvas_id, x, y)
523
+ if not self.find_window.open:
524
+ self.itemconfig(self.find_window.canvas_id, state="normal")
525
+ self.find_window.open = True
526
+ self.find_window.window.reset(
527
+ **{
528
+ "menu_kwargs": DotDict(
529
+ {
530
+ "font": self.PAR.ops.table_font,
531
+ "foreground": self.PAR.ops.popup_menu_fg,
532
+ "background": self.PAR.ops.popup_menu_bg,
533
+ "activebackground": self.PAR.ops.popup_menu_highlight_bg,
534
+ "activeforeground": self.PAR.ops.popup_menu_highlight_fg,
535
+ }
536
+ ),
537
+ "sheet_ops": self.PAR.ops,
538
+ "border_color": self.PAR.ops.table_selected_box_cells_fg,
539
+ "bg": self.PAR.ops.table_editor_bg,
540
+ "fg": self.PAR.ops.table_editor_fg,
541
+ "select_bg": self.PAR.ops.table_editor_select_bg,
542
+ "select_fg": self.PAR.ops.table_editor_select_fg,
543
+ }
544
+ )
545
+ self.itemconfig(self.find_window.canvas_id, width=width, height=height)
546
+ if focus:
547
+ self.find_window.tktext.focus_set()
548
+ return "break"
549
+
550
+ def find_see_and_set(self, coords: tuple[int, int] | None, just_see: bool = False) -> tuple[int, int]:
551
+ if coords:
552
+ if not self.all_rows_displayed:
553
+ coords = (self.disprn(coords[0]), coords[1])
554
+ if not self.all_columns_displayed:
555
+ coords = (coords[0], self.dispcn(coords[1]))
556
+ if not just_see:
557
+ if self.find_window.window.find_in_selection:
558
+ self.set_currently_selected(*coords)
559
+ else:
560
+ self.select_cell(*coords, redraw=False)
561
+ if not self.see(
562
+ *coords,
563
+ keep_yscroll=False,
564
+ keep_xscroll=False,
565
+ bottom_right_corner=False,
566
+ check_cell_visibility=True,
567
+ redraw=True,
568
+ ):
569
+ self.refresh()
570
+ return coords
571
+
572
+ def find_gen_all_cells(
573
+ self,
574
+ start_row: int,
575
+ start_col: int,
576
+ total_cols: int | None = None,
577
+ reverse: bool = False,
578
+ ) -> Generator[tuple[int, int]]:
579
+ if total_cols is None:
580
+ total_cols = self.total_data_cols(include_header=False)
581
+ total_rows = self.total_data_rows(include_index=False)
582
+ if reverse:
583
+ # yield start cell
584
+ yield (start_row, start_col)
585
+ # yield any remaining cells in the starting row before the start column
586
+ if start_col:
587
+ for col in reversed(range(start_col)):
588
+ yield (start_row, col)
589
+ # yield any cells above start row
590
+ for row in reversed(range(start_row)):
591
+ for col in reversed(range(total_cols)):
592
+ yield (row, col)
593
+ # yield cells from bottom of table upward
594
+ for row in range(total_rows - 1, start_row, -1):
595
+ for col in reversed(range(total_cols)):
596
+ yield (row, col)
597
+ # yield any remaining cells in start row
598
+ for col in range(total_cols - 1, start_col, -1):
599
+ yield (start_row, col)
600
+ else:
601
+ # Yield cells from the start position to the end of the current row
602
+ for col in range(start_col, total_cols):
603
+ yield (start_row, col)
604
+ # yield from the next row to the last row
605
+ for row in range(start_row + 1, total_rows):
606
+ for col in range(total_cols):
607
+ yield (row, col)
608
+ # yield from the beginning up to the start
609
+ for row in range(start_row):
610
+ for col in range(total_cols):
611
+ yield (row, col)
612
+ # yield any remaining cells in the starting row before the start column
613
+ for col in range(start_col):
614
+ yield (start_row, col)
615
+
616
+ def find_get_start_coords(
617
+ self,
618
+ plus_one: bool = True,
619
+ within: None | list = None,
620
+ reverse: bool = False,
621
+ ) -> tuple[int, int, int]:
622
+ selected = self.selected
623
+ if not selected:
624
+ return 0, 0, 0
625
+ max_row = len(self.row_positions) - 2
626
+ max_col = len(self.col_positions) - 2
627
+ row, col = selected.row, selected.column
628
+ if plus_one and within:
629
+ curridx = bisect_left(within, (row, col)) + (1 if not reverse else -1)
630
+ return row, col, curridx % len(within)
631
+ if plus_one:
632
+ if reverse:
633
+ if col == 0:
634
+ col = max_col
635
+ row = max_row if row == 0 else row - 1
636
+ else:
637
+ col -= 1
638
+ else:
639
+ col = (col + 1) % (max_col + 1)
640
+ if col == 0:
641
+ row = (row + 1) % (max_row + 1)
642
+ return row, col, 0
643
+
644
+ def find_match(self, find: str, r: int, c: int) -> bool:
645
+ return (
646
+ not find
647
+ and (not self.get_valid_cell_data_as_str(r, c, True).lower() or not f"{self.get_cell_data(r, c)}".lower())
648
+ ) or (
649
+ find
650
+ and (
651
+ find in self.get_valid_cell_data_as_str(r, c, True).lower()
652
+ or find in f"{self.get_cell_data(r, c)}".lower()
653
+ )
654
+ )
655
+
656
+ def find_within_sels(
657
+ self,
658
+ find: str,
659
+ reverse: bool = False,
660
+ ) -> tuple[int, int] | None:
661
+ sels = self.PAR.get_selected_cells(
662
+ get_rows=True,
663
+ get_columns=True,
664
+ sort_by_row=True,
665
+ sort_by_column=True,
666
+ )
667
+ _, _, from_idx = self.find_get_start_coords(plus_one=True, within=sels, reverse=reverse)
668
+ for r, c in chain(islice(sels, from_idx, None), islice(sels, 0, from_idx)):
669
+ if not self.all_rows_displayed:
670
+ r = self.datarn(r)
671
+ if not self.all_columns_displayed:
672
+ c = self.datacn(c)
673
+ if self.find_match(find, r, c):
674
+ return (r, c)
675
+ return None
676
+
677
+ def find_all_cells(
678
+ self,
679
+ find: str,
680
+ reverse: bool = False,
681
+ ) -> tuple[int, int] | None:
682
+ row, col, _ = self.find_get_start_coords(plus_one=True, reverse=reverse)
683
+ row, col = self.datarn(row), self.datacn(col)
684
+ return next(
685
+ (
686
+ (r, c)
687
+ for r, c in self.find_gen_all_cells(
688
+ start_row=row,
689
+ start_col=col,
690
+ total_cols=self.total_data_cols(include_header=False),
691
+ reverse=reverse,
692
+ )
693
+ if (
694
+ (self.all_rows_displayed or bisect_in(self.displayed_rows, r))
695
+ and (self.all_columns_displayed or bisect_in(self.displayed_columns, c))
696
+ and self.find_match(find, r, c)
697
+ )
698
+ ),
699
+ None,
700
+ )
701
+
702
+ def find_next(self, event: tk.Misc | None = None) -> Literal["break"]:
703
+ find = self.find_window.get().lower()
704
+ if not self.find_window.open:
705
+ self.open_find_window(focus=False)
706
+ if self.find_window.window.find_in_selection:
707
+ self.find_see_and_set(self.find_within_sels(find))
708
+ else:
709
+ self.find_see_and_set(self.find_all_cells(find))
710
+ return "break"
711
+
712
+ def find_previous(self, event: tk.Misc | None = None) -> Literal["break"]:
713
+ find = self.find_window.get().lower()
714
+ if not self.find_window.open:
715
+ self.open_find_window(focus=False)
716
+ if self.find_window.window.find_in_selection:
717
+ self.find_see_and_set(self.find_within_sels(find, reverse=True))
718
+ else:
719
+ self.find_see_and_set(self.find_all_cells(find, reverse=True))
720
+ return "break"
721
+
722
+ def close_find_window(
723
+ self,
724
+ event: tk.Misc | None = None,
725
+ ) -> None:
726
+ if self.find_window.open:
727
+ self.itemconfig(self.find_window.canvas_id, state="hidden")
728
+ self.find_window.open = False
729
+ self.focus_set()
730
+
475
731
  def create_ctrl_outline(
476
732
  self,
477
733
  x1: int,
@@ -523,19 +779,19 @@ class MainTable(tk.Canvas):
523
779
  self.hidd_ctrl_outline[t] = False
524
780
 
525
781
  def get_ctrl_x_c_boxes(self) -> tuple[dict[tuple[int, int, int, int], str], int]:
526
- boxes = {}
527
782
  maxrows = 0
528
783
  if not self.selected:
529
- return boxes, maxrows
784
+ return {}, maxrows
530
785
  if self.selected.type_ in ("cells", "columns"):
531
786
  curr_box = self.selection_boxes[self.selected.fill_iid].coords
532
787
  maxrows = curr_box[2] - curr_box[0]
533
- for item, box in self.get_selection_items(rows=False):
534
- if maxrows >= box.coords[2] - box.coords[0]:
535
- boxes[box.coords] = box.type_
788
+ boxes = {
789
+ box.coords: box.type_
790
+ for _, box in self.get_selection_items(rows=False)
791
+ if maxrows >= box.coords[2] - box.coords[0]
792
+ }
536
793
  else:
537
- for item, box in self.get_selection_items(columns=False, cells=False):
538
- boxes[box.coords] = "rows"
794
+ boxes = {box.coords: "rows" for _, box in self.get_selection_items(columns=False, cells=False)}
539
795
  return boxes, maxrows
540
796
 
541
797
  def io_csv_writer(self) -> tuple[io.StringIO, csv.writer]:
@@ -1746,23 +2002,23 @@ class MainTable(tk.Canvas):
1746
2002
  y = self.row_positions[r]
1747
2003
  else:
1748
2004
  y = self.row_positions[r + 1] + 1 - winfo_height
2005
+ y = y / (self.row_positions[-1] + self.PAR.ops.empty_vertical)
1749
2006
  args = [
1750
2007
  "moveto",
1751
- y / (self.row_positions[-1] + self.PAR.ops.empty_vertical),
2008
+ y - 1 if y > 1 else y,
1752
2009
  ]
1753
- if args[1] > 1:
1754
- args[1] = args[1] - 1
1755
2010
  self.set_yviews(*args, redraw=False)
1756
2011
  need_redraw = True
1757
2012
  else:
1758
2013
  if r is not None and not keep_yscroll:
1759
- y = self.row_positions[r] + ((self.row_positions[r + 1] - self.row_positions[r]) * r_pc)
2014
+ y = int(self.row_positions[r] + ((self.row_positions[r + 1] - self.row_positions[r]) * r_pc)) - 2
2015
+ if y < 0:
2016
+ y = 0
2017
+ y = y / (self.row_positions[-1] + self.PAR.ops.empty_vertical)
1760
2018
  args = [
1761
2019
  "moveto",
1762
- y / (self.row_positions[-1] + self.PAR.ops.empty_vertical),
2020
+ y - 1 if y > 1 else y,
1763
2021
  ]
1764
- if args[1] > 1:
1765
- args[1] = args[1] - 1
1766
2022
  self.set_yviews(*args, redraw=False)
1767
2023
  need_redraw = True
1768
2024
  if not xvis and len(self.col_positions) > 1:
@@ -1773,18 +2029,22 @@ class MainTable(tk.Canvas):
1773
2029
  x = self.col_positions[c]
1774
2030
  else:
1775
2031
  x = self.col_positions[c + 1] + 1 - winfo_width
2032
+ x = x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal)
1776
2033
  args = [
1777
2034
  "moveto",
1778
- x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal),
2035
+ x - 1 if x > 1 else x,
1779
2036
  ]
1780
2037
  self.set_xviews(*args, redraw=False)
1781
2038
  need_redraw = True
1782
2039
  else:
1783
2040
  if c is not None and not keep_xscroll:
1784
- x = self.col_positions[c] + ((self.col_positions[c + 1] - self.col_positions[c]) * c_pc)
2041
+ x = int(self.col_positions[c] + ((self.col_positions[c + 1] - self.col_positions[c]) * c_pc)) - 2
2042
+ if x < 0:
2043
+ x = 0
2044
+ x = x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal)
1785
2045
  args = [
1786
2046
  "moveto",
1787
- x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal),
2047
+ x - 1 if x > 1 else x,
1788
2048
  ]
1789
2049
  self.set_xviews(*args, redraw=False)
1790
2050
  need_redraw = True
@@ -1806,20 +2066,12 @@ class MainTable(tk.Canvas):
1806
2066
  r: int | None = 0,
1807
2067
  c: int | None = 0,
1808
2068
  separate_axes: bool = False,
1809
- ) -> bool:
2069
+ ) -> bool | tuple[bool, bool]:
1810
2070
  cx1, cy1, cx2, cy2 = self.get_canvas_visible_area()
1811
2071
  x1, y1, x2, y2 = self.get_cell_coords(r, c)
1812
- x_vis = True
1813
- y_vis = True
1814
- if cx1 > x1 or cx2 < x2:
1815
- x_vis = False
1816
- if cy1 > y1 or cy2 < y2:
1817
- y_vis = False
1818
- if separate_axes:
1819
- return y_vis, x_vis
1820
- if not y_vis or not x_vis:
1821
- return False
1822
- return True
2072
+ x_vis = cx1 <= x1 and cx2 >= x2
2073
+ y_vis = cy1 <= y1 and cy2 >= y2
2074
+ return (y_vis, x_vis) if separate_axes else y_vis and x_vis
1823
2075
 
1824
2076
  def cell_visible(self, r: int = 0, c: int = 0) -> bool:
1825
2077
  cx1, cy1, cx2, cy2 = self.get_canvas_visible_area()
@@ -1844,14 +2096,43 @@ class MainTable(tk.Canvas):
1844
2096
  if redraw:
1845
2097
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
1846
2098
  if run_binding_func:
1847
- if self.select_all_binding_func:
1848
- self.select_all_binding_func(
1849
- self.get_select_event(being_drawn_item=self.being_drawn_item),
1850
- )
1851
2099
  event_data = self.get_select_event(self.being_drawn_item)
2100
+ try_binding(self.select_all_binding_func, event_data)
1852
2101
  self.PAR.emit_event("<<SheetSelect>>", data=event_data)
1853
2102
  self.PAR.emit_event("<<SelectAll>>", data=event_data)
1854
2103
 
2104
+ def select_columns(self, event: object) -> None:
2105
+ if not self.selected:
2106
+ return
2107
+ r1, c1, r2, c2 = self.selection_boxes[self.selected.fill_iid].coords
2108
+ r, c = self.selected.row, self.selected.column
2109
+ self.set_currently_selected(
2110
+ r=r,
2111
+ c=c,
2112
+ item=self.CH.select_col(range(c1, c2), redraw=True),
2113
+ )
2114
+
2115
+ def select_rows(self, event: object) -> None:
2116
+ if not self.selected:
2117
+ return
2118
+ r1, c1, r2, c2 = self.selection_boxes[self.selected.fill_iid].coords
2119
+ r, c = self.selected.row, self.selected.column
2120
+ self.set_currently_selected(
2121
+ r=r,
2122
+ c=c,
2123
+ item=self.RI.select_row(range(r1, r2), redraw=True),
2124
+ )
2125
+
2126
+ def select_row_start(self, event: object) -> None:
2127
+ if self.selected:
2128
+ self.see(self.selected.row, 0)
2129
+ self.select_cell(self.selected.row, 0, redraw=True)
2130
+
2131
+ def select_a1(self, event: object) -> None:
2132
+ if len(self.row_positions) > 1 and len(self.col_positions) > 1:
2133
+ self.see(0, 0)
2134
+ self.select_cell(0, 0, redraw=True)
2135
+
1855
2136
  def select_cell(
1856
2137
  self,
1857
2138
  r: int,
@@ -1934,7 +2215,9 @@ class MainTable(tk.Canvas):
1934
2215
  ) -> None:
1935
2216
  if not self.selected:
1936
2217
  return
2218
+ curr_box = self.selected.fill_iid
1937
2219
  if r == "all" or (r is None and c is None and cell is None):
2220
+ self.hide_dropdown_editor_all_canvases()
1938
2221
  for item, box in self.get_selection_items():
1939
2222
  self.hide_selection_box(item)
1940
2223
  elif r in ("allrows", "allcols"):
@@ -1944,6 +2227,8 @@ class MainTable(tk.Canvas):
1944
2227
  cells=False,
1945
2228
  ):
1946
2229
  self.hide_selection_box(item)
2230
+ if item == curr_box:
2231
+ self.hide_dropdown_editor_all_canvases()
1947
2232
  elif isinstance(r, int) and c is None and cell is None:
1948
2233
  for item, box in self.get_selection_items(columns=False, cells=False):
1949
2234
  r1, c1, r2, c2 = box.coords
@@ -1951,6 +2236,8 @@ class MainTable(tk.Canvas):
1951
2236
  resel = self.selected.fill_iid == item
1952
2237
  to_sel = self.selected.row
1953
2238
  self.hide_selection_box(item)
2239
+ if item == curr_box:
2240
+ self.hide_dropdown_editor_all_canvases()
1954
2241
  if r2 - r1 != 1:
1955
2242
  if r == r1:
1956
2243
  self.create_selection_box(
@@ -1994,6 +2281,8 @@ class MainTable(tk.Canvas):
1994
2281
  resel = self.selected.fill_iid == item
1995
2282
  to_sel = self.selected.column
1996
2283
  self.hide_selection_box(item)
2284
+ if item == curr_box:
2285
+ self.hide_dropdown_editor_all_canvases()
1997
2286
  if c2 - c1 != 1:
1998
2287
  if c == c1:
1999
2288
  self.create_selection_box(
@@ -2037,6 +2326,8 @@ class MainTable(tk.Canvas):
2037
2326
  r1, c1, r2, c2 = box.coords
2038
2327
  if r >= r1 and c >= c1 and r < r2 and c < c2:
2039
2328
  self.hide_selection_box(item)
2329
+ if item == curr_box:
2330
+ self.hide_text_editor_and_dropdown(redraw=False)
2040
2331
  if redraw:
2041
2332
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
2042
2333
  sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
@@ -2046,12 +2337,15 @@ class MainTable(tk.Canvas):
2046
2337
 
2047
2338
  def deselect_any(
2048
2339
  self,
2049
- rows: Iterator[int] | int | None = None,
2050
- columns: Iterator[int] | int | None = None,
2340
+ rows: AnyIter[int] | int | None = None,
2341
+ columns: AnyIter[int] | int | None = None,
2051
2342
  redraw: bool = True,
2052
2343
  ) -> None:
2344
+ if not self.selected:
2345
+ return
2053
2346
  rows = int_x_iter(rows)
2054
2347
  columns = int_x_iter(columns)
2348
+ curr_box = self.selected.fill_iid
2055
2349
  if is_iterable(rows) and is_iterable(columns):
2056
2350
  rows = tuple(consecutive_ranges(sorted(rows)))
2057
2351
  columns = tuple(consecutive_ranges(sorted(columns)))
@@ -2066,6 +2360,8 @@ class MainTable(tk.Canvas):
2066
2360
  (cols_end >= c1 and cols_end <= c2) or (cols_st >= c1 and cols_st < c2)
2067
2361
  ):
2068
2362
  hidden = self.hide_selection_box(item)
2363
+ if item == curr_box:
2364
+ self.hide_dropdown_editor_all_canvases()
2069
2365
  break
2070
2366
  elif is_iterable(rows):
2071
2367
  rows = tuple(consecutive_ranges(sorted(rows)))
@@ -2074,6 +2370,8 @@ class MainTable(tk.Canvas):
2074
2370
  for rows_st, rows_end in rows:
2075
2371
  if (rows_end >= r1 and rows_end <= r2) or (rows_st >= r1 and rows_st < r2):
2076
2372
  self.hide_selection_box(item)
2373
+ if item == curr_box:
2374
+ self.hide_dropdown_editor_all_canvases()
2077
2375
  break
2078
2376
  elif is_iterable(columns):
2079
2377
  columns = tuple(consecutive_ranges(sorted(columns)))
@@ -2082,6 +2380,8 @@ class MainTable(tk.Canvas):
2082
2380
  for cols_st, cols_end in columns:
2083
2381
  if (cols_end >= c1 and cols_end <= c2) or (cols_st >= c1 and cols_st < c2):
2084
2382
  self.hide_selection_box(item)
2383
+ if item == curr_box:
2384
+ self.hide_dropdown_editor_all_canvases()
2085
2385
  break
2086
2386
  else:
2087
2387
  self.deselect()
@@ -2161,9 +2461,8 @@ class MainTable(tk.Canvas):
2161
2461
  elif self.selected.type_ in ("cells", "columns"):
2162
2462
  r = self.selected.row
2163
2463
  c = self.selected.column
2164
- if not r and self.CH.col_selection_enabled:
2165
- if not self.cell_completely_visible(r=r, c=0):
2166
- self.see(r, c, check_cell_visibility=False)
2464
+ if not r and self.CH.col_selection_enabled and not self.cell_completely_visible(r=r, c=c):
2465
+ self.see(r, c, check_cell_visibility=False)
2167
2466
  elif r and (self.single_selection_enabled or self.toggle_selection_enabled):
2168
2467
  if self.cell_completely_visible(r=r - 1, c=c):
2169
2468
  self.select_cell(r - 1, c, redraw=True)
@@ -2177,32 +2476,18 @@ class MainTable(tk.Canvas):
2177
2476
  if self.selected.type_ == "rows":
2178
2477
  r = self.selected.row
2179
2478
  if r < len(self.row_positions) - 2 and self.RI.row_selection_enabled:
2180
- if self.cell_completely_visible(r=min(r + 2, len(self.row_positions) - 2), c=0):
2479
+ if self.cell_completely_visible(r=r + 1, c=0):
2181
2480
  self.RI.select_row(r + 1, redraw=True)
2182
2481
  else:
2183
2482
  self.RI.select_row(r + 1)
2184
- if (
2185
- r + 2 < len(self.row_positions) - 2
2186
- and (self.row_positions[r + 3] - self.row_positions[r + 2])
2187
- + (self.row_positions[r + 2] - self.row_positions[r + 1])
2188
- + 5
2189
- < self.winfo_height()
2190
- ):
2191
- self.see(
2192
- r + 2,
2193
- 0,
2194
- keep_xscroll=True,
2195
- bottom_right_corner=True,
2196
- check_cell_visibility=False,
2197
- )
2198
- elif not self.cell_completely_visible(r=r + 1, c=0):
2199
- self.see(
2200
- r + 1,
2201
- 0,
2202
- keep_xscroll=True,
2203
- bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2204
- check_cell_visibility=False,
2205
- )
2483
+ self.see(
2484
+ r + 1,
2485
+ 0,
2486
+ keep_xscroll=True,
2487
+ bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2488
+ check_cell_visibility=False,
2489
+ )
2490
+
2206
2491
  elif self.selected.type_ == "columns":
2207
2492
  c = self.selected.column
2208
2493
  if self.single_selection_enabled or self.toggle_selection_enabled:
@@ -2223,32 +2508,17 @@ class MainTable(tk.Canvas):
2223
2508
  r = self.selected.row
2224
2509
  c = self.selected.column
2225
2510
  if r < len(self.row_positions) - 2 and (self.single_selection_enabled or self.toggle_selection_enabled):
2226
- if self.cell_completely_visible(r=min(r + 2, len(self.row_positions) - 2), c=c):
2511
+ if self.cell_completely_visible(r=r + 1, c=c):
2227
2512
  self.select_cell(r + 1, c, redraw=True)
2228
2513
  else:
2229
2514
  self.select_cell(r + 1, c)
2230
- if (
2231
- r + 2 < len(self.row_positions) - 2
2232
- and (self.row_positions[r + 3] - self.row_positions[r + 2])
2233
- + (self.row_positions[r + 2] - self.row_positions[r + 1])
2234
- + 5
2235
- < self.winfo_height()
2236
- ):
2237
- self.see(
2238
- r + 2,
2239
- c,
2240
- keep_xscroll=True,
2241
- bottom_right_corner=True,
2242
- check_cell_visibility=False,
2243
- )
2244
- elif not self.cell_completely_visible(r=r + 1, c=c):
2245
- self.see(
2246
- r + 1,
2247
- c,
2248
- keep_xscroll=True,
2249
- bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2250
- check_cell_visibility=False,
2251
- )
2515
+ self.see(
2516
+ r + 1,
2517
+ c,
2518
+ keep_xscroll=True,
2519
+ bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2520
+ check_cell_visibility=False,
2521
+ )
2252
2522
 
2253
2523
  def arrowkey_LEFT(self, event: object = None) -> None:
2254
2524
  if not self.selected:
@@ -2273,7 +2543,7 @@ class MainTable(tk.Canvas):
2273
2543
  elif self.selected.type_ == "cells":
2274
2544
  r = self.selected.row
2275
2545
  c = self.selected.column
2276
- if not c and not self.cell_completely_visible(r=r, c=0):
2546
+ if not c and not self.cell_completely_visible(r=r, c=c):
2277
2547
  self.see(r, c, keep_yscroll=True, check_cell_visibility=False)
2278
2548
  elif c and (self.single_selection_enabled or self.toggle_selection_enabled):
2279
2549
  if self.cell_completely_visible(r=r, c=c - 1):
@@ -2658,7 +2928,7 @@ class MainTable(tk.Canvas):
2658
2928
  **mnkwgs,
2659
2929
  )
2660
2930
 
2661
- def enable_bindings(self, bindings):
2931
+ def enable_bindings(self, bindings: object) -> None:
2662
2932
  if not bindings:
2663
2933
  self._enable_binding("all")
2664
2934
  elif isinstance(bindings, (list, tuple)):
@@ -2672,7 +2942,7 @@ class MainTable(tk.Canvas):
2672
2942
  self._enable_binding(bindings.lower())
2673
2943
  self.create_rc_menus()
2674
2944
 
2675
- def disable_bindings(self, bindings):
2945
+ def disable_bindings(self, bindings: object) -> None:
2676
2946
  if not bindings:
2677
2947
  self._disable_binding("all")
2678
2948
  elif isinstance(bindings, (list, tuple)):
@@ -2686,21 +2956,34 @@ class MainTable(tk.Canvas):
2686
2956
  self._disable_binding(bindings)
2687
2957
  self.create_rc_menus()
2688
2958
 
2689
- def _enable_binding(self, binding):
2959
+ def _enable_binding(self, binding: str) -> None:
2690
2960
  if binding == "enable_all":
2691
2961
  binding = "all"
2692
- if binding in ("all", "single", "single_selection_mode", "single_select"):
2693
- self.single_selection_enabled = True
2694
- self.toggle_selection_enabled = False
2695
- elif binding in ("toggle", "toggle_selection_mode", "toggle_select"):
2696
- self.toggle_selection_enabled = True
2697
- self.single_selection_enabled = False
2962
+ if binding in (
2963
+ "all",
2964
+ "single",
2965
+ "single_selection_mode",
2966
+ "single_select",
2967
+ "toggle",
2968
+ "toggle_selection_mode",
2969
+ "toggle_select",
2970
+ ):
2971
+ self._tksheet_bind("row_start_bindings", self.select_row_start)
2972
+ self._tksheet_bind("table_start_bindings", self.select_a1)
2973
+ self._tksheet_bind("escape_bindings", self.escape)
2974
+ if binding in ("all", "single", "single_selection_mode", "single_select"):
2975
+ self.single_selection_enabled = True
2976
+ self.toggle_selection_enabled = False
2977
+ elif binding in ("toggle", "toggle_selection_mode", "toggle_select"):
2978
+ self.toggle_selection_enabled = True
2979
+ self.single_selection_enabled = False
2698
2980
  if binding in ("all", "drag_select"):
2699
2981
  self.drag_selection_enabled = True
2700
2982
  if binding in ("all", "column_width_resize"):
2701
2983
  self.CH.width_resizing_enabled = True
2702
2984
  if binding in ("all", "column_select"):
2703
2985
  self.CH.col_selection_enabled = True
2986
+ self._tksheet_bind("select_columns_bindings", self.select_columns)
2704
2987
  if binding in ("all", "column_height_resize"):
2705
2988
  self.CH.height_resizing_enabled = True
2706
2989
  self.TL.rh_state()
@@ -2717,6 +3000,7 @@ class MainTable(tk.Canvas):
2717
3000
  self.TL.rw_state()
2718
3001
  if binding in ("all", "row_select"):
2719
3002
  self.RI.row_selection_enabled = True
3003
+ self._tksheet_bind("select_rows_bindings", self.select_rows)
2720
3004
  if binding in ("all", "row_drag_and_drop", "move_rows"):
2721
3005
  self.RI.drag_and_drop_enabled = True
2722
3006
  if binding in ("all", "select_all"):
@@ -2764,6 +3048,11 @@ class MainTable(tk.Canvas):
2764
3048
  self.undo_enabled = True
2765
3049
  self._tksheet_bind("undo_bindings", self.undo)
2766
3050
  self._tksheet_bind("redo_bindings", self.redo)
3051
+ if binding in ("find",):
3052
+ self.find_enabled = True
3053
+ self._tksheet_bind("find_bindings", self.open_find_window)
3054
+ self._tksheet_bind("find_next_bindings", self.find_next)
3055
+ self._tksheet_bind("find_previous_bindings", self.find_previous)
2767
3056
  if binding in bind_del_columns:
2768
3057
  self.rc_delete_column_enabled = True
2769
3058
  self.rc_popup_menus_enabled = True
@@ -2802,21 +3091,30 @@ class MainTable(tk.Canvas):
2802
3091
  for binding in self.PAR.ops[bindings_key]:
2803
3092
  widget.bind(binding, func)
2804
3093
 
2805
- def _disable_binding(self, binding):
3094
+ def _disable_binding(self, binding: str) -> None:
2806
3095
  if binding == "disable_all":
2807
3096
  binding = "all"
2808
- if binding in ("all", "single", "single_selection_mode", "single_select"):
3097
+ if binding in (
3098
+ "all",
3099
+ "single",
3100
+ "single_selection_mode",
3101
+ "single_select",
3102
+ "toggle",
3103
+ "toggle_selection_mode",
3104
+ "toggle_select",
3105
+ ):
3106
+ self._tksheet_unbind("row_start_bindings")
3107
+ self._tksheet_unbind("table_start_bindings")
3108
+ self._tksheet_unbind("escape_bindings")
2809
3109
  self.single_selection_enabled = False
2810
3110
  self.toggle_selection_enabled = False
2811
- elif binding in ("toggle", "toggle_selection_mode", "toggle_select"):
2812
- self.toggle_selection_enabled = False
2813
- self.single_selection_enabled = False
2814
3111
  if binding in ("all", "drag_select"):
2815
3112
  self.drag_selection_enabled = False
2816
3113
  if binding in ("all", "column_width_resize"):
2817
3114
  self.CH.width_resizing_enabled = False
2818
3115
  if binding in ("all", "column_select"):
2819
3116
  self.CH.col_selection_enabled = False
3117
+ self._tksheet_unbind("select_columns_bindings")
2820
3118
  if binding in ("all", "column_height_resize"):
2821
3119
  self.CH.height_resizing_enabled = False
2822
3120
  self.TL.rh_state("hidden")
@@ -2833,6 +3131,7 @@ class MainTable(tk.Canvas):
2833
3131
  self.TL.rw_state("hidden")
2834
3132
  if binding in ("all", "row_select"):
2835
3133
  self.RI.row_selection_enabled = False
3134
+ self._tksheet_unbind("select_rows_bindings")
2836
3135
  if binding in ("all", "row_drag_and_drop", "move_rows"):
2837
3136
  self.RI.drag_and_drop_enabled = False
2838
3137
  if binding in bind_del_columns:
@@ -2897,6 +3196,12 @@ class MainTable(tk.Canvas):
2897
3196
  if binding in ("all", "undo", "redo", "edit_bindings", "edit"):
2898
3197
  self.undo_enabled = False
2899
3198
  self._tksheet_unbind("undo_bindings", "redo_bindings")
3199
+ if binding in ("all", "find"):
3200
+ self.find_enabled = False
3201
+ self._tksheet_unbind("find_bindings")
3202
+ self._tksheet_unbind("find_next_bindings")
3203
+ self._tksheet_unbind("find_previous_bindings")
3204
+ self.close_find_window()
2900
3205
 
2901
3206
  def _tksheet_unbind(self, *keys) -> None:
2902
3207
  for widget in (self, self.RI, self.CH, self.TL):
@@ -3383,26 +3688,42 @@ class MainTable(tk.Canvas):
3383
3688
  if move_synced:
3384
3689
  self.y_move_synced_scrolls(*args, use_scrollbar=True)
3385
3690
 
3386
- def set_xviews(self, *args, move_synced: bool = True, redraw: bool = True) -> None:
3691
+ def set_xviews(
3692
+ self,
3693
+ *args,
3694
+ move_synced: bool = True,
3695
+ redraw: bool = True,
3696
+ ) -> None:
3387
3697
  self.main_table_redraw_grid_and_text(setting_views=True)
3388
- self.update_idletasks()
3698
+ if not self.PAR._startup_complete:
3699
+ self.update_idletasks()
3389
3700
  self.xview(*args)
3390
3701
  if self.show_header:
3391
- self.CH.update_idletasks()
3702
+ if not self.PAR._startup_complete:
3703
+ self.CH.update_idletasks()
3392
3704
  self.CH.xview(*args)
3393
- self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=False)
3705
+ if redraw:
3706
+ self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=False)
3394
3707
  if move_synced:
3395
3708
  self.x_move_synced_scrolls(*args)
3396
3709
  self.fix_views()
3397
3710
 
3398
- def set_yviews(self, *args, move_synced: bool = True, redraw: bool = True) -> None:
3711
+ def set_yviews(
3712
+ self,
3713
+ *args,
3714
+ move_synced: bool = True,
3715
+ redraw: bool = True,
3716
+ ) -> None:
3399
3717
  self.main_table_redraw_grid_and_text(setting_views=True)
3400
- self.update_idletasks()
3718
+ if not self.PAR._startup_complete:
3719
+ self.update_idletasks()
3401
3720
  self.yview(*args)
3402
3721
  if self.show_index:
3403
- self.RI.update_idletasks()
3722
+ if not self.PAR._startup_complete:
3723
+ self.RI.update_idletasks()
3404
3724
  self.RI.yview(*args)
3405
- self.main_table_redraw_grid_and_text(redraw_header=False, redraw_row_index=True)
3725
+ if redraw:
3726
+ self.main_table_redraw_grid_and_text(redraw_header=False, redraw_row_index=True)
3406
3727
  if move_synced:
3407
3728
  self.y_move_synced_scrolls(*args)
3408
3729
  self.fix_views()
@@ -3544,7 +3865,7 @@ class MainTable(tk.Canvas):
3544
3865
  b = self.txt_measure_canvas.bbox(self.txt_measure_canvas_text)
3545
3866
  return b[3] - b[1]
3546
3867
 
3547
- def get_txt_dimensions(self, txt: str, font: None | FontTuple = None) -> int:
3868
+ def get_txt_dimensions(self, txt: str, font: None | FontTuple = None) -> tuple[int, int]:
3548
3869
  self.txt_measure_canvas.itemconfig(
3549
3870
  self.txt_measure_canvas_text,
3550
3871
  text=txt,
@@ -3565,7 +3886,6 @@ class MainTable(tk.Canvas):
3565
3886
  def set_min_column_width(self, width: int) -> None:
3566
3887
  if width:
3567
3888
  self.PAR.ops.min_column_width = width
3568
-
3569
3889
  if self.PAR.ops.min_column_width > self.PAR.ops.max_column_width:
3570
3890
  self.PAR.ops.max_column_width = self.PAR.ops.min_column_width + 20
3571
3891
  if (
@@ -3595,12 +3915,12 @@ class MainTable(tk.Canvas):
3595
3915
  def set_table_font(self, newfont: tuple | None = None, reset_row_positions: bool = False) -> tuple[str, int, str]:
3596
3916
  if newfont:
3597
3917
  if not isinstance(newfont, tuple):
3598
- raise ValueError("Argument must be tuple e.g. " "('Carlito', 12, 'normal')")
3918
+ raise ValueError("Argument must be tuple e.g. ('Carlito', 12, 'normal')")
3599
3919
  if len(newfont) != 3:
3600
3920
  raise ValueError("Argument must be three-tuple")
3601
3921
  if not isinstance(newfont[0], str) or not isinstance(newfont[1], int) or not isinstance(newfont[2], str):
3602
3922
  raise ValueError(
3603
- "Argument must be font, size and 'normal', 'bold' or" "'italic' e.g. ('Carlito',12,'normal')"
3923
+ "Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
3604
3924
  )
3605
3925
  self.PAR.ops.table_font = FontTuple(*newfont)
3606
3926
  self.set_table_font_help()
@@ -3632,7 +3952,7 @@ class MainTable(tk.Canvas):
3632
3952
  raise ValueError("Argument must be three-tuple")
3633
3953
  if not isinstance(newfont[0], str) or not isinstance(newfont[1], int) or not isinstance(newfont[2], str):
3634
3954
  raise ValueError(
3635
- "Argument must be font, size and 'normal', 'bold' or" "'italic' e.g. ('Carlito',12,'normal')"
3955
+ "Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
3636
3956
  )
3637
3957
  self.PAR.ops.header_font = FontTuple(*newfont)
3638
3958
  self.set_header_font_help()
@@ -3663,7 +3983,7 @@ class MainTable(tk.Canvas):
3663
3983
  raise ValueError("Argument must be three-tuple")
3664
3984
  if not isinstance(newfont[0], str) or not isinstance(newfont[1], int) or not isinstance(newfont[2], str):
3665
3985
  raise ValueError(
3666
- "Argument must be font, size and 'normal', 'bold' or" "'italic' e.g. ('Carlito',12,'normal')"
3986
+ "Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
3667
3987
  )
3668
3988
  self.PAR.ops.index_font = FontTuple(*newfont)
3669
3989
  self.set_index_font_help()
@@ -3880,7 +4200,7 @@ class MainTable(tk.Canvas):
3880
4200
  self.recreate_all_selection_boxes()
3881
4201
  return self.row_positions, self.col_positions
3882
4202
 
3883
- def set_col_positions(self, itr: Iterator[float]) -> None:
4203
+ def set_col_positions(self, itr: AnyIter[float]) -> None:
3884
4204
  self.col_positions = list(accumulate(chain([0], itr)))
3885
4205
 
3886
4206
  def reset_col_positions(self, ncols: int | None = None):
@@ -3892,7 +4212,7 @@ class MainTable(tk.Canvas):
3892
4212
  else:
3893
4213
  self.set_col_positions(itr=repeat(colpos, len(self.displayed_columns)))
3894
4214
 
3895
- def set_row_positions(self, itr: Iterator[float]) -> None:
4215
+ def set_row_positions(self, itr: AnyIter[float]) -> None:
3896
4216
  self.row_positions = list(accumulate(chain([0], itr)))
3897
4217
 
3898
4218
  def reset_row_positions(self, nrows: int | None = None):
@@ -3926,7 +4246,7 @@ class MainTable(tk.Canvas):
3926
4246
  del self.row_positions[idx]
3927
4247
  self.row_positions[idx:] = [e - w for e in islice(self.row_positions, idx, len(self.row_positions))]
3928
4248
 
3929
- def del_col_positions(self, idxs: Iterator[int] | None = None):
4249
+ def del_col_positions(self, idxs: AnyIter[int] | None = None):
3930
4250
  if idxs is None:
3931
4251
  del self.col_positions[-1]
3932
4252
  else:
@@ -3934,7 +4254,7 @@ class MainTable(tk.Canvas):
3934
4254
  idxs = set(idxs)
3935
4255
  self.set_col_positions(itr=(w for i, w in enumerate(self.gen_column_widths()) if i not in idxs))
3936
4256
 
3937
- def del_row_positions(self, idxs: Iterator[int] | None = None):
4257
+ def del_row_positions(self, idxs: AnyIter[int] | None = None):
3938
4258
  if idxs is None:
3939
4259
  del self.row_positions[-1]
3940
4260
  else:
@@ -4678,8 +4998,8 @@ class MainTable(tk.Canvas):
4678
4998
  data_ins_col: int,
4679
4999
  displayed_ins_col: int,
4680
5000
  numcols: int,
4681
- columns: list | None = None,
4682
- widths: list | None = None,
5001
+ columns: list[list[object]] | None = None,
5002
+ widths: list[int] | tuple[int] | None = None,
4683
5003
  headers: bool = False,
4684
5004
  ) -> tuple[dict, dict, dict]:
4685
5005
  header_data = {}
@@ -4728,10 +5048,10 @@ class MainTable(tk.Canvas):
4728
5048
  data_ins_row: int,
4729
5049
  displayed_ins_row: int,
4730
5050
  numrows: int,
4731
- rows: list | None = None,
4732
- heights: list | None = None,
5051
+ rows: list[list[object]] | None = None,
5052
+ heights: list[int] | tuple[int] | None = None,
4733
5053
  row_index: bool = False,
4734
- total_data_cols=None,
5054
+ total_data_cols: int | None = None,
4735
5055
  ) -> tuple[dict, dict, dict]:
4736
5056
  index_data = {}
4737
5057
  if isinstance(self._row_index, list):
@@ -4934,7 +5254,7 @@ class MainTable(tk.Canvas):
4934
5254
 
4935
5255
  def display_rows(
4936
5256
  self,
4937
- rows: int | Iterator | None = None,
5257
+ rows: int | AnyIter[int] | None = None,
4938
5258
  all_rows_displayed: bool | None = None,
4939
5259
  reset_row_positions: bool = True,
4940
5260
  deselect_all: bool = True,
@@ -4963,7 +5283,7 @@ class MainTable(tk.Canvas):
4963
5283
 
4964
5284
  def display_columns(
4965
5285
  self,
4966
- columns: int | Iterator | None = None,
5286
+ columns: int | AnyIter[int] | None = None,
4967
5287
  all_columns_displayed: bool | None = None,
4968
5288
  reset_col_positions: bool = True,
4969
5289
  deselect_all: bool = True,
@@ -5568,11 +5888,18 @@ class MainTable(tk.Canvas):
5568
5888
  if resized_cols or resized_rows or changed_w:
5569
5889
  self.recreate_all_selection_boxes()
5570
5890
  if changed_w:
5571
- self.update_idletasks()
5572
- self.RI.update_idletasks()
5573
- self.CH.update_idletasks()
5574
- self.TL.update_idletasks()
5891
+ for widget in (self, self.RI, self.CH, self.TL):
5892
+ widget.update_idletasks()
5575
5893
  return False
5894
+ if self.find_window.open:
5895
+ w, h, x, y = self.get_find_window_dimensions_coords(w_width=self.winfo_width())
5896
+ self.coords(self.find_window.canvas_id, x, y)
5897
+ self.itemconfig(
5898
+ self.find_window.canvas_id,
5899
+ width=w,
5900
+ height=h,
5901
+ state="normal",
5902
+ )
5576
5903
  self.hidd_text.update(self.disp_text)
5577
5904
  self.disp_text = {}
5578
5905
  self.hidd_high.update(self.disp_high)
@@ -5603,13 +5930,13 @@ class MainTable(tk.Canvas):
5603
5930
  chain.from_iterable(
5604
5931
  [
5605
5932
  (
5606
- self.canvasx(0) - 1,
5933
+ scrollpos_left - 1,
5607
5934
  self.row_positions[r],
5608
5935
  x_grid_stop,
5609
5936
  self.row_positions[r],
5610
- self.canvasx(0) - 1,
5937
+ scrollpos_left - 1,
5611
5938
  self.row_positions[r],
5612
- self.canvasx(0) - 1,
5939
+ scrollpos_left - 1,
5613
5940
  self.row_positions[r + 1] if len(self.row_positions) - 1 > r else self.row_positions[r],
5614
5941
  )
5615
5942
  for r in range(grid_start_row, grid_end_row)
@@ -5971,56 +6298,35 @@ class MainTable(tk.Canvas):
5971
6298
  box: tuple[int, int, int, int] | None = None,
5972
6299
  run_binding: bool = True,
5973
6300
  ) -> None:
6301
+ def box_created(r: int, c: int, box: SelectionBox) -> bool:
6302
+ r1, c1, r2, c2 = box.coords
6303
+ if r1 <= r and c1 <= c and r2 >= r and c2 >= c:
6304
+ self.create_currently_selected_box(r, c, box.type_, box.fill_iid)
6305
+ if run_binding:
6306
+ self.run_selection_binding(box.type_)
6307
+ return True
6308
+ return False
6309
+
6310
+ # set current to a particular existing selection box
5974
6311
  if isinstance(item, int) and item in self.selection_boxes:
5975
6312
  selection_box = self.selection_boxes[item]
5976
6313
  r1, c1, r2, c2 = selection_box.coords
5977
- if r is None:
5978
- r = r1
5979
- if c is None:
5980
- c = c1
5981
- if r1 <= r and c1 <= c and r2 >= r and c2 >= c:
5982
- self.create_currently_selected_box(
5983
- r,
5984
- c,
5985
- selection_box.type_,
5986
- selection_box.fill_iid,
5987
- )
5988
- if run_binding:
5989
- self.run_selection_binding(selection_box.type_)
6314
+ if box_created(r1 if r is None else r, c1 if c is None else c, selection_box):
5990
6315
  return
5991
- # currently selected is pointed at any selection box with "box" coordinates
6316
+
6317
+ # set current to any existing selection box with coordinates: box
5992
6318
  if isinstance(box, tuple):
5993
- if r is None:
5994
- r = box[0]
5995
- if c is None:
5996
- c = box[1]
5997
6319
  for item, selection_box in self.get_selection_items(reverse=True):
5998
- r1, c1, r2, c2 = selection_box.coords
5999
- if box == (r1, c1, r2, c2) and r1 <= r and c1 <= c and r2 >= r and c2 >= c:
6000
- self.create_currently_selected_box(
6001
- r,
6002
- c,
6003
- selection_box.type_,
6004
- selection_box.fill_iid,
6005
- )
6006
- if run_binding:
6007
- self.run_selection_binding(selection_box.type_)
6008
- return
6009
- # currently selected is just pointed at a coordinate
6010
- # find the top most box there, requires r and c
6011
- if r is not None and c is not None:
6320
+ if box == selection_box.coords:
6321
+ if box_created(box[0] if r is None else r, box[1] if c is None else c, selection_box):
6322
+ return
6323
+
6324
+ # set current to a coordinate, find the top most box there
6325
+ if isinstance(r, int) and isinstance(c, int):
6012
6326
  for item, selection_box in self.get_selection_items(reverse=True):
6013
- r1, c1, r2, c2 = selection_box.coords
6014
- if r1 <= r and c1 <= c and r2 >= r and c2 >= c:
6015
- self.create_currently_selected_box(
6016
- r,
6017
- c,
6018
- selection_box.type_,
6019
- selection_box.fill_iid,
6020
- )
6021
- if run_binding:
6022
- self.run_selection_binding(selection_box.type_)
6327
+ if box_created(r, c, selection_box):
6023
6328
  return
6329
+
6024
6330
  # wasn't provided an item and couldn't find a box at coords so select cell
6025
6331
  if r < len(self.row_positions) - 1 and c < len(self.col_positions) - 1:
6026
6332
  self.select_cell(r, c, redraw=True)
@@ -6141,7 +6447,7 @@ class MainTable(tk.Canvas):
6141
6447
 
6142
6448
  def hide_selection_box(self, item: int | None) -> bool:
6143
6449
  if item is None or item is True or item not in self.selection_boxes:
6144
- return
6450
+ return False
6145
6451
  box = self.selection_boxes.pop(item)
6146
6452
  self.hide_box(box.fill_iid)
6147
6453
  self.hide_box(box.bd_iid)
@@ -6391,50 +6697,30 @@ class MainTable(tk.Canvas):
6391
6697
  def recreate_all_selection_boxes(self) -> None:
6392
6698
  if not self.selected:
6393
6699
  return
6700
+
6394
6701
  modified = False
6702
+ row_limit = len(self.row_positions) - 1
6703
+ col_limit = len(self.col_positions) - 1
6704
+
6395
6705
  for item, box in self.get_selection_items():
6396
6706
  r1, c1, r2, c2 = box.coords
6397
- if not modified:
6398
- modified = (
6399
- r1 >= len(self.row_positions) - 1
6400
- or c1 >= len(self.col_positions) - 1
6401
- or r2 > len(self.row_positions) - 1
6402
- or c2 > len(self.col_positions) - 1
6403
- )
6404
- if r1 >= len(self.row_positions) - 1:
6405
- if len(self.row_positions) > 1:
6406
- r1 = len(self.row_positions) - 2
6407
- else:
6408
- r1 = 0
6409
- if c1 >= len(self.col_positions) - 1:
6410
- if len(self.col_positions) > 1:
6411
- c1 = len(self.col_positions) - 2
6412
- else:
6413
- c1 = 0
6414
- if r2 > len(self.row_positions) - 1:
6415
- r2 = len(self.row_positions) - 1
6416
- if c2 > len(self.col_positions) - 1:
6417
- c2 = len(self.col_positions) - 1
6707
+ # check coordinates
6708
+ r1 = min(r1, row_limit - (1 if row_limit > 0 else 0))
6709
+ c1 = min(c1, col_limit - (1 if col_limit > 0 else 0))
6710
+ r2 = min(r2, row_limit)
6711
+ c2 = min(c2, col_limit)
6712
+
6713
+ modified = modified or (r1 >= row_limit or c1 >= col_limit or r2 > row_limit or c2 > col_limit)
6418
6714
  self.recreate_selection_box(r1, c1, r2, c2, item, run_binding=False)
6419
6715
 
6420
6716
  if self.selected:
6421
- r = self.selected.row
6422
- c = self.selected.column
6423
- if r < len(self.row_positions) - 1 and c < len(self.col_positions) - 1:
6424
- self.set_currently_selected(
6425
- r,
6426
- c,
6427
- item=self.selected.fill_iid,
6428
- run_binding=False,
6429
- )
6717
+ r, c = self.selected.row, self.selected.column
6718
+ if r < row_limit and c < col_limit:
6719
+ self.set_currently_selected(r, c, item=self.selected.fill_iid, run_binding=False)
6430
6720
  else:
6431
6721
  box = self.selection_boxes[self.selected.fill_iid]
6432
- self.set_currently_selected(
6433
- box.coords.from_r,
6434
- box.coords.from_c,
6435
- item=box.fill_iid,
6436
- run_binding=False,
6437
- )
6722
+ self.set_currently_selected(box.coords[0], box.coords[1], item=box.fill_iid, run_binding=False)
6723
+
6438
6724
  if modified:
6439
6725
  self.PAR.emit_event(
6440
6726
  "<<SheetSelect>>",
@@ -6461,23 +6747,17 @@ class MainTable(tk.Canvas):
6461
6747
  return d
6462
6748
 
6463
6749
  def get_selected_min_max(self) -> tuple[int, int, int, int] | tuple[None, None, None, None]:
6464
- min_x = float("inf")
6465
- min_y = float("inf")
6466
- max_x = 0
6467
- max_y = 0
6468
- for item, box in self.get_selection_items():
6750
+ if not self.get_selection_items():
6751
+ return None, None, None, None
6752
+ min_y, min_x = float("inf"), float("inf")
6753
+ max_y, max_x = 0, 0
6754
+
6755
+ for _, box in self.get_selection_items():
6469
6756
  r1, c1, r2, c2 = box.coords
6470
- if r1 < min_y:
6471
- min_y = r1
6472
- if c1 < min_x:
6473
- min_x = c1
6474
- if r2 > max_y:
6475
- max_y = r2
6476
- if c2 > max_x:
6477
- max_x = c2
6478
- if min_x != float("inf") and min_y != float("inf") and max_x > 0 and max_y > 0:
6479
- return min_y, min_x, max_y, max_x
6480
- return None, None, None, None
6757
+ min_y, min_x = min(min_y, r1), min(min_x, c1)
6758
+ max_y, max_x = max(max_y, r2), max(max_x, c2)
6759
+
6760
+ return (min_y, min_x, max_y, max_x) if min_y != float("inf") else (None, None, None, None)
6481
6761
 
6482
6762
  def get_selected_rows(
6483
6763
  self,
@@ -6632,7 +6912,7 @@ class MainTable(tk.Canvas):
6632
6912
  elif self.get_cell_kwargs(datarn, datacn, key="dropdown") or self.get_cell_kwargs(
6633
6913
  datarn, datacn, key="checkbox"
6634
6914
  ):
6635
- if self.event_opens_dropdown_or_checkbox(event):
6915
+ if event_opens_dropdown_or_checkbox(event):
6636
6916
  if self.get_cell_kwargs(datarn, datacn, key="dropdown"):
6637
6917
  self.open_dropdown_window(r, c, event=event)
6638
6918
  elif self.get_cell_kwargs(datarn, datacn, key="checkbox"):
@@ -6640,27 +6920,6 @@ class MainTable(tk.Canvas):
6640
6920
  else:
6641
6921
  self.open_text_editor(event=event, r=r, c=c, dropdown=False)
6642
6922
 
6643
- def event_opens_dropdown_or_checkbox(self, event=None) -> bool:
6644
- if event is None:
6645
- return False
6646
- elif event == "rc":
6647
- return True
6648
- elif (
6649
- (hasattr(event, "keysym") and event.keysym == "Return")
6650
- or (hasattr(event, "keysym") and event.keysym == "F2")
6651
- or (
6652
- event is not None
6653
- and hasattr(event, "keycode")
6654
- and event.keycode == "??"
6655
- and hasattr(event, "num")
6656
- and event.num == 1
6657
- ) # mouseclick
6658
- or (hasattr(event, "keysym") and event.keysym == "BackSpace")
6659
- ):
6660
- return True
6661
- else:
6662
- return False
6663
-
6664
6923
  # displayed indexes
6665
6924
  def get_cell_align(self, r: int, c: int) -> str:
6666
6925
  datarn = self.datarn(r)
@@ -6680,27 +6939,16 @@ class MainTable(tk.Canvas):
6680
6939
  state: str = "normal",
6681
6940
  dropdown: bool = False,
6682
6941
  ) -> bool:
6683
- text = None
6942
+ text = f"{self.get_cell_data(self.datarn(r), self.datacn(c), none_to_empty_str=True)}"
6684
6943
  extra_func_key = "??"
6685
- if event is None or self.event_opens_dropdown_or_checkbox(event):
6686
- if event is not None:
6687
- if hasattr(event, "keysym") and event.keysym == "Return":
6688
- extra_func_key = "Return"
6689
- elif hasattr(event, "keysym") and event.keysym == "F2":
6690
- extra_func_key = "F2"
6691
- if event is not None and (hasattr(event, "keysym") and event.keysym == "BackSpace"):
6692
- extra_func_key = "BackSpace"
6693
- text = ""
6694
- else:
6695
- text = f"{self.get_cell_data(self.datarn(r), self.datacn(c), none_to_empty_str = True)}"
6696
- elif event is not None and (
6697
- (hasattr(event, "char") and event.char.isalpha())
6698
- or (hasattr(event, "char") and event.char.isdigit())
6699
- or (hasattr(event, "char") and event.char in symbols_set)
6700
- ):
6701
- extra_func_key = event.char
6702
- text = event.char
6703
- else:
6944
+ if event_opens_dropdown_or_checkbox(event):
6945
+ if hasattr(event, "keysym") and event.keysym in ("Return", "F2", "BackSpace"):
6946
+ extra_func_key = event.keysym
6947
+ if event.keysym == "BackSpace":
6948
+ text = ""
6949
+ elif event_has_char_key(event):
6950
+ extra_func_key = text = event.char
6951
+ elif event is not None:
6704
6952
  return False
6705
6953
  if self.extra_begin_edit_cell_func:
6706
6954
  try:
@@ -6723,12 +6971,11 @@ class MainTable(tk.Canvas):
6723
6971
  return False
6724
6972
  else:
6725
6973
  text = text if isinstance(text, str) else f"{text}"
6726
- text = "" if text is None else text
6727
6974
  if self.PAR.ops.cell_auto_resize_enabled:
6728
6975
  self.set_cell_size_to_text(r, c, only_if_too_small=True, redraw=True, run_binding=True)
6729
6976
  if self.text_editor.open and (r, c) == self.text_editor.coords:
6730
6977
  self.text_editor.window.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
6731
- return
6978
+ return False
6732
6979
  self.hide_text_editor()
6733
6980
  if not self.see(r=r, c=c, check_cell_visibility=True):
6734
6981
  self.refresh()
@@ -6736,8 +6983,6 @@ class MainTable(tk.Canvas):
6736
6983
  y = self.row_positions[r]
6737
6984
  w = self.col_positions[c + 1] - x + 1
6738
6985
  h = self.row_positions[r + 1] - y + 1
6739
- if text is None:
6740
- text = f"{self.get_cell_data(self.datarn(r), self.datacn(c), none_to_empty_str = True)}"
6741
6986
  kwargs = {
6742
6987
  "menu_kwargs": DotDict(
6743
6988
  {