tksheet 7.3.1__py3-none-any.whl → 7.3.3__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
@@ -39,6 +39,22 @@ from typing import Literal
39
39
  from .colors import (
40
40
  color_map,
41
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
+ )
42
58
  from .formatters import (
43
59
  data_to_str,
44
60
  format_data,
@@ -50,6 +66,8 @@ from .formatters import (
50
66
  from .functions import (
51
67
  add_to_displayed,
52
68
  b_index,
69
+ bisect_in,
70
+ box_gen_coords,
53
71
  box_is_single_cell,
54
72
  cell_right_within_box,
55
73
  color_tup,
@@ -58,7 +76,10 @@ from .functions import (
58
76
  diff_list,
59
77
  down_cell_within_box,
60
78
  event_dict,
79
+ event_has_char_key,
80
+ event_opens_dropdown_or_checkbox,
61
81
  float_to_int,
82
+ gen_coords,
62
83
  gen_formatted,
63
84
  get_data_from_clipboard,
64
85
  get_new_indexes,
@@ -67,6 +88,7 @@ from .functions import (
67
88
  insert_items,
68
89
  int_x_iter,
69
90
  is_iterable,
91
+ is_last_cell,
70
92
  is_type_int,
71
93
  len_to_idx,
72
94
  mod_event_val,
@@ -74,6 +96,7 @@ from .functions import (
74
96
  mod_span_widget,
75
97
  move_elements_by_mapping,
76
98
  new_tk_event,
99
+ next_cell,
77
100
  rounded_box_coords,
78
101
  span_idxs_post_move,
79
102
  stored_event_dict,
@@ -86,6 +109,7 @@ from .other_classes import (
86
109
  Box_t,
87
110
  DotDict,
88
111
  DropdownStorage,
112
+ EditorStorageBase,
89
113
  EventDataDict,
90
114
  FontTuple,
91
115
  Highlight,
@@ -101,20 +125,6 @@ from .text_editor import (
101
125
  from .types import (
102
126
  AnyIter,
103
127
  )
104
- from .vars import (
105
- USER_OS,
106
- bind_add_columns,
107
- bind_add_rows,
108
- bind_del_columns,
109
- bind_del_rows,
110
- ctrl_key,
111
- rc_binding,
112
- symbols_set,
113
- text_editor_close_bindings,
114
- text_editor_newline_bindings,
115
- text_editor_to_unbind,
116
- val_modifying_options,
117
- )
118
128
 
119
129
 
120
130
  class MainTable(tk.Canvas):
@@ -140,6 +150,7 @@ class MainTable(tk.Canvas):
140
150
  self.synced_scrolls = set()
141
151
  self.dropdown = DropdownStorage()
142
152
  self.text_editor = TextEditorStorage()
153
+ self.find_window = EditorStorageBase()
143
154
  self.event_linker = {
144
155
  "<<Copy>>": self.ctrl_c,
145
156
  "<<Cut>>": self.ctrl_x,
@@ -248,6 +259,7 @@ class MainTable(tk.Canvas):
248
259
  self.drag_selection_enabled = False
249
260
  self.select_all_enabled = False
250
261
  self.undo_enabled = False
262
+ self.find_enabled = False
251
263
  self.cut_enabled = False
252
264
  self.copy_enabled = False
253
265
  self.paste_enabled = False
@@ -476,6 +488,250 @@ class MainTable(tk.Canvas):
476
488
  if delete_on_timer:
477
489
  self.after(1500, self.delete_ctrl_outlines)
478
490
 
491
+ def escape(self, event: tk.Misc | None) -> None:
492
+ if self.find_window.open:
493
+ self.close_find_window()
494
+ else:
495
+ self.deselect()
496
+
497
+ def get_find_window_dimensions_coords(self, w_width: int) -> tuple[int, int, int, int]:
498
+ width = min(self.get_txt_w("X" * 23), w_width - 7)
499
+ # w, h, x, y
500
+ return width, self.min_row_height, self.canvasx(max(0, w_width - width - 7)), self.canvasy(7)
501
+
502
+ def open_find_window(
503
+ self,
504
+ event: tk.Misc | None = None,
505
+ focus: bool = True,
506
+ ) -> Literal["break"]:
507
+ if self.find_window.open:
508
+ self.close_find_window()
509
+ return "break"
510
+ width, height, x, y = self.get_find_window_dimensions_coords(w_width=self.winfo_width())
511
+ if not self.find_window.window:
512
+ self.find_window.window = FindWindow(
513
+ self,
514
+ find_prev_func=self.find_previous,
515
+ find_next_func=self.find_next,
516
+ close_func=self.close_find_window,
517
+ )
518
+ self.find_window.canvas_id = self.create_window((x, y), window=self.find_window.window, anchor="nw")
519
+ for b in chain(self.PAR.ops.escape_bindings, self.PAR.ops.find_bindings):
520
+ self.find_window.tktext.bind(b, self.close_find_window)
521
+ for b in chain(self.PAR.ops.find_next_bindings, ("<Return>", "<KP_Enter>")):
522
+ self.find_window.tktext.bind(b, self.find_next)
523
+ for b in self.PAR.ops.find_previous_bindings:
524
+ self.find_window.tktext.bind(b, self.find_previous)
525
+ else:
526
+ self.coords(self.find_window.canvas_id, x, y)
527
+ if not self.find_window.open:
528
+ self.itemconfig(self.find_window.canvas_id, state="normal")
529
+ self.find_window.open = True
530
+ self.find_window.window.reset(
531
+ **{
532
+ "menu_kwargs": DotDict(
533
+ {
534
+ "font": self.PAR.ops.table_font,
535
+ "foreground": self.PAR.ops.popup_menu_fg,
536
+ "background": self.PAR.ops.popup_menu_bg,
537
+ "activebackground": self.PAR.ops.popup_menu_highlight_bg,
538
+ "activeforeground": self.PAR.ops.popup_menu_highlight_fg,
539
+ }
540
+ ),
541
+ "sheet_ops": self.PAR.ops,
542
+ "border_color": self.PAR.ops.table_selected_box_cells_fg,
543
+ "bg": self.PAR.ops.table_editor_bg,
544
+ "fg": self.PAR.ops.table_editor_fg,
545
+ "select_bg": self.PAR.ops.table_editor_select_bg,
546
+ "select_fg": self.PAR.ops.table_editor_select_fg,
547
+ }
548
+ )
549
+ self.itemconfig(self.find_window.canvas_id, width=width, height=height)
550
+ if focus:
551
+ self.find_window.tktext.focus_set()
552
+ return "break"
553
+
554
+ def find_see_and_set(
555
+ self,
556
+ coords: tuple[int, int, int | None] | None,
557
+ just_see: bool = False,
558
+ ) -> tuple[int, int]:
559
+ if coords:
560
+ row, column, item = coords
561
+ if not self.all_rows_displayed:
562
+ row = self.disprn(row)
563
+ if not self.all_columns_displayed:
564
+ column = self.dispcn(column)
565
+ if not just_see:
566
+ if self.find_window.window.find_in_selection:
567
+ self.set_currently_selected(row, column, item=item)
568
+ else:
569
+ self.select_cell(row, column, redraw=False)
570
+ if not self.see(
571
+ row,
572
+ column,
573
+ keep_yscroll=False,
574
+ keep_xscroll=False,
575
+ bottom_right_corner=False,
576
+ check_cell_visibility=True,
577
+ redraw=True,
578
+ ):
579
+ self.refresh()
580
+ return coords
581
+
582
+ def find_match(self, find: str, r: int, c: int) -> bool:
583
+ return (
584
+ not find
585
+ and (not self.get_valid_cell_data_as_str(r, c, True).lower() or not f"{self.get_cell_data(r, c)}".lower())
586
+ ) or (
587
+ find
588
+ and (
589
+ find in self.get_valid_cell_data_as_str(r, c, True).lower()
590
+ or find in f"{self.get_cell_data(r, c)}".lower()
591
+ )
592
+ )
593
+
594
+ def find_within_match(self, find: str, r: int, c: int) -> bool:
595
+ if not self.all_rows_displayed:
596
+ r = self.datarn(r)
597
+ if not self.all_columns_displayed:
598
+ c = self.datacn(c)
599
+ return self.find_match(find, r, c)
600
+
601
+ def find_within_current_box(
602
+ self,
603
+ current_box: SelectionBox,
604
+ find: str,
605
+ reverse: bool,
606
+ ) -> None | tuple[int, int]:
607
+ start_row, start_col = next_cell(
608
+ *current_box.coords,
609
+ self.selected.row,
610
+ self.selected.column,
611
+ reverse=reverse,
612
+ )
613
+ _, _, r2, c2 = current_box.coords
614
+ for r, c in box_gen_coords(start_row, start_col, c2, r2, reverse=reverse):
615
+ if self.find_within_match(find, r, c):
616
+ return (r, c, current_box.fill_iid)
617
+ return None
618
+
619
+ def find_within_non_current_boxes(
620
+ self,
621
+ current_id: int,
622
+ find: str,
623
+ reverse: bool,
624
+ ) -> None | tuple[int, int]:
625
+ if reverse:
626
+ # iterate backwards through selection boxes from the box before current
627
+ idx = next(i for i, k in enumerate(reversed(self.selection_boxes)) if k == current_id)
628
+ for item, box in chain(
629
+ islice(reversed(self.selection_boxes.items()), idx + 1, None),
630
+ islice(reversed(self.selection_boxes.items()), 0, idx),
631
+ ):
632
+ for r, c in gen_coords(*box.coords, reverse=reverse):
633
+ if self.find_within_match(find, r, c):
634
+ return (r, c, item)
635
+ else:
636
+ # iterate forwards through selection boxes from the box after current
637
+ idx = next(i for i, k in enumerate(self.selection_boxes) if k == current_id)
638
+ for item, box in chain(
639
+ islice(self.selection_boxes.items(), idx + 1, None),
640
+ islice(self.selection_boxes.items(), 0, idx),
641
+ ):
642
+ for r, c in gen_coords(*box.coords, reverse=reverse):
643
+ if self.find_within_match(find, r, c):
644
+ return (r, c, item)
645
+ return None
646
+
647
+ def find_within(
648
+ self,
649
+ find: str,
650
+ reverse: bool = False,
651
+ ) -> tuple[int, int, int] | None:
652
+ current_box = self.selection_boxes[self.selected.fill_iid]
653
+ current_id = self.selected.fill_iid
654
+ if is_last_cell(*current_box.coords, self.selected.row, self.selected.column, reverse=reverse):
655
+ if coord := self.find_within_non_current_boxes(current_id=current_id, find=find, reverse=reverse):
656
+ return coord
657
+ if coord := self.find_within_current_box(current_box=current_box, find=find, reverse=reverse):
658
+ return coord
659
+ else:
660
+ if coord := self.find_within_current_box(current_box=current_box, find=find, reverse=reverse):
661
+ return coord
662
+ if coord := self.find_within_non_current_boxes(current_id=current_id, find=find, reverse=reverse):
663
+ return coord
664
+ return None
665
+
666
+ def find_all_cells(
667
+ self,
668
+ find: str,
669
+ reverse: bool = False,
670
+ ) -> tuple[int, int, None] | None:
671
+ if self.selected:
672
+ row, col = next_cell(
673
+ 0,
674
+ 0,
675
+ len(self.row_positions) - 1,
676
+ len(self.col_positions) - 1,
677
+ self.selected.row,
678
+ self.selected.column,
679
+ reverse=reverse,
680
+ )
681
+ else:
682
+ row, col = 0, 0
683
+ row, col = self.datarn(row), self.datacn(col)
684
+ result = next(
685
+ (
686
+ (r, c)
687
+ for r, c in box_gen_coords(
688
+ start_row=row,
689
+ start_col=col,
690
+ total_cols=self.total_data_cols(include_header=False),
691
+ total_rows=self.total_data_rows(include_index=False),
692
+ reverse=reverse,
693
+ )
694
+ if (
695
+ (self.all_rows_displayed or bisect_in(self.displayed_rows, r))
696
+ and (self.all_columns_displayed or bisect_in(self.displayed_columns, c))
697
+ and self.find_match(find, r, c)
698
+ )
699
+ ),
700
+ None,
701
+ )
702
+ if result:
703
+ return result + (None,)
704
+ return None
705
+
706
+ def find_next(self, event: tk.Misc | None = None) -> Literal["break"]:
707
+ find = self.find_window.get().lower()
708
+ if not self.find_window.open:
709
+ self.open_find_window(focus=False)
710
+ if self.find_window.window.find_in_selection:
711
+ self.find_see_and_set(self.find_within(find))
712
+ else:
713
+ self.find_see_and_set(self.find_all_cells(find))
714
+ return "break"
715
+
716
+ def find_previous(self, event: tk.Misc | None = None) -> Literal["break"]:
717
+ find = self.find_window.get().lower()
718
+ if not self.find_window.open:
719
+ self.open_find_window(focus=False)
720
+ if self.find_window.window.find_in_selection:
721
+ self.find_see_and_set(self.find_within(find, reverse=True))
722
+ else:
723
+ self.find_see_and_set(self.find_all_cells(find, reverse=True))
724
+ return "break"
725
+
726
+ def close_find_window(
727
+ self,
728
+ event: tk.Misc | None = None,
729
+ ) -> None:
730
+ if self.find_window.open:
731
+ self.itemconfig(self.find_window.canvas_id, state="hidden")
732
+ self.find_window.open = False
733
+ self.focus_set()
734
+
479
735
  def create_ctrl_outline(
480
736
  self,
481
737
  x1: int,
@@ -527,19 +783,19 @@ class MainTable(tk.Canvas):
527
783
  self.hidd_ctrl_outline[t] = False
528
784
 
529
785
  def get_ctrl_x_c_boxes(self) -> tuple[dict[tuple[int, int, int, int], str], int]:
530
- boxes = {}
531
786
  maxrows = 0
532
787
  if not self.selected:
533
- return boxes, maxrows
788
+ return {}, maxrows
534
789
  if self.selected.type_ in ("cells", "columns"):
535
790
  curr_box = self.selection_boxes[self.selected.fill_iid].coords
536
791
  maxrows = curr_box[2] - curr_box[0]
537
- for item, box in self.get_selection_items(rows=False):
538
- if maxrows >= box.coords[2] - box.coords[0]:
539
- boxes[box.coords] = box.type_
792
+ boxes = {
793
+ box.coords: box.type_
794
+ for _, box in self.get_selection_items(rows=False)
795
+ if maxrows >= box.coords[2] - box.coords[0]
796
+ }
540
797
  else:
541
- for item, box in self.get_selection_items(columns=False, cells=False):
542
- boxes[box.coords] = "rows"
798
+ boxes = {box.coords: "rows" for _, box in self.get_selection_items(columns=False, cells=False)}
543
799
  return boxes, maxrows
544
800
 
545
801
  def io_csv_writer(self) -> tuple[io.StringIO, csv.writer]:
@@ -964,25 +1220,24 @@ class MainTable(tk.Canvas):
964
1220
  event_data["selection_boxes"] = boxes
965
1221
  if not try_binding(self.extra_begin_delete_key_func, event_data, "begin_delete"):
966
1222
  return
967
- for r1, c1, r2, c2 in boxes:
968
- for r in range(r1, r2):
969
- for c in range(c1, c2):
970
- datarn, datacn = self.datarn(r), self.datacn(c)
971
- val = self.get_value_for_empty_cell(datarn, datacn)
972
- if (
973
- not self.edit_validation_func
974
- or not validation
975
- or (
976
- self.edit_validation_func
977
- and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
978
- )
979
- ):
980
- event_data = self.event_data_set_cell(
981
- datarn,
982
- datacn,
983
- val,
984
- event_data,
985
- )
1223
+ for box in boxes:
1224
+ for r, c in gen_coords(*box):
1225
+ datarn, datacn = self.datarn(r), self.datacn(c)
1226
+ val = self.get_value_for_empty_cell(datarn, datacn)
1227
+ if (
1228
+ not self.edit_validation_func
1229
+ or not validation
1230
+ or (
1231
+ self.edit_validation_func
1232
+ and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
1233
+ )
1234
+ ):
1235
+ event_data = self.event_data_set_cell(
1236
+ datarn,
1237
+ datacn,
1238
+ val,
1239
+ event_data,
1240
+ )
986
1241
  if event_data["cells"]["table"]:
987
1242
  self.refresh()
988
1243
  self.undo_stack.append(stored_event_dict(event_data))
@@ -1750,23 +2005,23 @@ class MainTable(tk.Canvas):
1750
2005
  y = self.row_positions[r]
1751
2006
  else:
1752
2007
  y = self.row_positions[r + 1] + 1 - winfo_height
2008
+ y = y / (self.row_positions[-1] + self.PAR.ops.empty_vertical)
1753
2009
  args = [
1754
2010
  "moveto",
1755
- y / (self.row_positions[-1] + self.PAR.ops.empty_vertical),
2011
+ y - 1 if y > 1 else y,
1756
2012
  ]
1757
- if args[1] > 1:
1758
- args[1] = args[1] - 1
1759
2013
  self.set_yviews(*args, redraw=False)
1760
2014
  need_redraw = True
1761
2015
  else:
1762
2016
  if r is not None and not keep_yscroll:
1763
- y = self.row_positions[r] + ((self.row_positions[r + 1] - self.row_positions[r]) * r_pc)
2017
+ y = int(self.row_positions[r] + ((self.row_positions[r + 1] - self.row_positions[r]) * r_pc)) - 2
2018
+ if y < 0:
2019
+ y = 0
2020
+ y = y / (self.row_positions[-1] + self.PAR.ops.empty_vertical)
1764
2021
  args = [
1765
2022
  "moveto",
1766
- y / (self.row_positions[-1] + self.PAR.ops.empty_vertical),
2023
+ y - 1 if y > 1 else y,
1767
2024
  ]
1768
- if args[1] > 1:
1769
- args[1] = args[1] - 1
1770
2025
  self.set_yviews(*args, redraw=False)
1771
2026
  need_redraw = True
1772
2027
  if not xvis and len(self.col_positions) > 1:
@@ -1777,18 +2032,22 @@ class MainTable(tk.Canvas):
1777
2032
  x = self.col_positions[c]
1778
2033
  else:
1779
2034
  x = self.col_positions[c + 1] + 1 - winfo_width
2035
+ x = x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal)
1780
2036
  args = [
1781
2037
  "moveto",
1782
- x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal),
2038
+ x - 1 if x > 1 else x,
1783
2039
  ]
1784
2040
  self.set_xviews(*args, redraw=False)
1785
2041
  need_redraw = True
1786
2042
  else:
1787
2043
  if c is not None and not keep_xscroll:
1788
- x = self.col_positions[c] + ((self.col_positions[c + 1] - self.col_positions[c]) * c_pc)
2044
+ x = int(self.col_positions[c] + ((self.col_positions[c + 1] - self.col_positions[c]) * c_pc)) - 2
2045
+ if x < 0:
2046
+ x = 0
2047
+ x = x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal)
1789
2048
  args = [
1790
2049
  "moveto",
1791
- x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal),
2050
+ x - 1 if x > 1 else x,
1792
2051
  ]
1793
2052
  self.set_xviews(*args, redraw=False)
1794
2053
  need_redraw = True
@@ -1810,20 +2069,12 @@ class MainTable(tk.Canvas):
1810
2069
  r: int | None = 0,
1811
2070
  c: int | None = 0,
1812
2071
  separate_axes: bool = False,
1813
- ) -> bool:
2072
+ ) -> bool | tuple[bool, bool]:
1814
2073
  cx1, cy1, cx2, cy2 = self.get_canvas_visible_area()
1815
2074
  x1, y1, x2, y2 = self.get_cell_coords(r, c)
1816
- x_vis = True
1817
- y_vis = True
1818
- if cx1 > x1 or cx2 < x2:
1819
- x_vis = False
1820
- if cy1 > y1 or cy2 < y2:
1821
- y_vis = False
1822
- if separate_axes:
1823
- return y_vis, x_vis
1824
- if not y_vis or not x_vis:
1825
- return False
1826
- return True
2075
+ x_vis = cx1 <= x1 and cx2 >= x2
2076
+ y_vis = cy1 <= y1 and cy2 >= y2
2077
+ return (y_vis, x_vis) if separate_axes else y_vis and x_vis
1827
2078
 
1828
2079
  def cell_visible(self, r: int = 0, c: int = 0) -> bool:
1829
2080
  cx1, cy1, cx2, cy2 = self.get_canvas_visible_area()
@@ -1877,13 +2128,13 @@ class MainTable(tk.Canvas):
1877
2128
 
1878
2129
  def select_row_start(self, event: object) -> None:
1879
2130
  if self.selected:
1880
- self.select_cell(self.selected.row, 0)
1881
2131
  self.see(self.selected.row, 0)
2132
+ self.select_cell(self.selected.row, 0, redraw=True)
1882
2133
 
1883
2134
  def select_a1(self, event: object) -> None:
1884
2135
  if len(self.row_positions) > 1 and len(self.col_positions) > 1:
1885
- self.select_cell(0, 0)
1886
2136
  self.see(0, 0)
2137
+ self.select_cell(0, 0, redraw=True)
1887
2138
 
1888
2139
  def select_cell(
1889
2140
  self,
@@ -2213,9 +2464,8 @@ class MainTable(tk.Canvas):
2213
2464
  elif self.selected.type_ in ("cells", "columns"):
2214
2465
  r = self.selected.row
2215
2466
  c = self.selected.column
2216
- if not r and self.CH.col_selection_enabled:
2217
- if not self.cell_completely_visible(r=r, c=0):
2218
- self.see(r, c, check_cell_visibility=False)
2467
+ if not r and self.CH.col_selection_enabled and not self.cell_completely_visible(r=r, c=c):
2468
+ self.see(r, c, check_cell_visibility=False)
2219
2469
  elif r and (self.single_selection_enabled or self.toggle_selection_enabled):
2220
2470
  if self.cell_completely_visible(r=r - 1, c=c):
2221
2471
  self.select_cell(r - 1, c, redraw=True)
@@ -2229,32 +2479,18 @@ class MainTable(tk.Canvas):
2229
2479
  if self.selected.type_ == "rows":
2230
2480
  r = self.selected.row
2231
2481
  if r < len(self.row_positions) - 2 and self.RI.row_selection_enabled:
2232
- if self.cell_completely_visible(r=min(r + 2, len(self.row_positions) - 2), c=0):
2482
+ if self.cell_completely_visible(r=r + 1, c=0):
2233
2483
  self.RI.select_row(r + 1, redraw=True)
2234
2484
  else:
2235
2485
  self.RI.select_row(r + 1)
2236
- if (
2237
- r + 2 < len(self.row_positions) - 2
2238
- and (self.row_positions[r + 3] - self.row_positions[r + 2])
2239
- + (self.row_positions[r + 2] - self.row_positions[r + 1])
2240
- + 5
2241
- < self.winfo_height()
2242
- ):
2243
- self.see(
2244
- r + 2,
2245
- 0,
2246
- keep_xscroll=True,
2247
- bottom_right_corner=True,
2248
- check_cell_visibility=False,
2249
- )
2250
- elif not self.cell_completely_visible(r=r + 1, c=0):
2251
- self.see(
2252
- r + 1,
2253
- 0,
2254
- keep_xscroll=True,
2255
- bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2256
- check_cell_visibility=False,
2257
- )
2486
+ self.see(
2487
+ r + 1,
2488
+ 0,
2489
+ keep_xscroll=True,
2490
+ bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2491
+ check_cell_visibility=False,
2492
+ )
2493
+
2258
2494
  elif self.selected.type_ == "columns":
2259
2495
  c = self.selected.column
2260
2496
  if self.single_selection_enabled or self.toggle_selection_enabled:
@@ -2275,32 +2511,17 @@ class MainTable(tk.Canvas):
2275
2511
  r = self.selected.row
2276
2512
  c = self.selected.column
2277
2513
  if r < len(self.row_positions) - 2 and (self.single_selection_enabled or self.toggle_selection_enabled):
2278
- if self.cell_completely_visible(r=min(r + 2, len(self.row_positions) - 2), c=c):
2514
+ if self.cell_completely_visible(r=r + 1, c=c):
2279
2515
  self.select_cell(r + 1, c, redraw=True)
2280
2516
  else:
2281
2517
  self.select_cell(r + 1, c)
2282
- if (
2283
- r + 2 < len(self.row_positions) - 2
2284
- and (self.row_positions[r + 3] - self.row_positions[r + 2])
2285
- + (self.row_positions[r + 2] - self.row_positions[r + 1])
2286
- + 5
2287
- < self.winfo_height()
2288
- ):
2289
- self.see(
2290
- r + 2,
2291
- c,
2292
- keep_xscroll=True,
2293
- bottom_right_corner=True,
2294
- check_cell_visibility=False,
2295
- )
2296
- elif not self.cell_completely_visible(r=r + 1, c=c):
2297
- self.see(
2298
- r + 1,
2299
- c,
2300
- keep_xscroll=True,
2301
- bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2302
- check_cell_visibility=False,
2303
- )
2518
+ self.see(
2519
+ r + 1,
2520
+ c,
2521
+ keep_xscroll=True,
2522
+ bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2523
+ check_cell_visibility=False,
2524
+ )
2304
2525
 
2305
2526
  def arrowkey_LEFT(self, event: object = None) -> None:
2306
2527
  if not self.selected:
@@ -2325,7 +2546,7 @@ class MainTable(tk.Canvas):
2325
2546
  elif self.selected.type_ == "cells":
2326
2547
  r = self.selected.row
2327
2548
  c = self.selected.column
2328
- if not c and not self.cell_completely_visible(r=r, c=0):
2549
+ if not c and not self.cell_completely_visible(r=r, c=c):
2329
2550
  self.see(r, c, keep_yscroll=True, check_cell_visibility=False)
2330
2551
  elif c and (self.single_selection_enabled or self.toggle_selection_enabled):
2331
2552
  if self.cell_completely_visible(r=r, c=c - 1):
@@ -2710,7 +2931,7 @@ class MainTable(tk.Canvas):
2710
2931
  **mnkwgs,
2711
2932
  )
2712
2933
 
2713
- def enable_bindings(self, bindings):
2934
+ def enable_bindings(self, bindings: object) -> None:
2714
2935
  if not bindings:
2715
2936
  self._enable_binding("all")
2716
2937
  elif isinstance(bindings, (list, tuple)):
@@ -2752,6 +2973,7 @@ class MainTable(tk.Canvas):
2752
2973
  ):
2753
2974
  self._tksheet_bind("row_start_bindings", self.select_row_start)
2754
2975
  self._tksheet_bind("table_start_bindings", self.select_a1)
2976
+ self._tksheet_bind("escape_bindings", self.escape)
2755
2977
  if binding in ("all", "single", "single_selection_mode", "single_select"):
2756
2978
  self.single_selection_enabled = True
2757
2979
  self.toggle_selection_enabled = False
@@ -2829,6 +3051,11 @@ class MainTable(tk.Canvas):
2829
3051
  self.undo_enabled = True
2830
3052
  self._tksheet_bind("undo_bindings", self.undo)
2831
3053
  self._tksheet_bind("redo_bindings", self.redo)
3054
+ if binding in ("find",):
3055
+ self.find_enabled = True
3056
+ self._tksheet_bind("find_bindings", self.open_find_window)
3057
+ self._tksheet_bind("find_next_bindings", self.find_next)
3058
+ self._tksheet_bind("find_previous_bindings", self.find_previous)
2832
3059
  if binding in bind_del_columns:
2833
3060
  self.rc_delete_column_enabled = True
2834
3061
  self.rc_popup_menus_enabled = True
@@ -2881,6 +3108,7 @@ class MainTable(tk.Canvas):
2881
3108
  ):
2882
3109
  self._tksheet_unbind("row_start_bindings")
2883
3110
  self._tksheet_unbind("table_start_bindings")
3111
+ self._tksheet_unbind("escape_bindings")
2884
3112
  self.single_selection_enabled = False
2885
3113
  self.toggle_selection_enabled = False
2886
3114
  if binding in ("all", "drag_select"):
@@ -2971,6 +3199,12 @@ class MainTable(tk.Canvas):
2971
3199
  if binding in ("all", "undo", "redo", "edit_bindings", "edit"):
2972
3200
  self.undo_enabled = False
2973
3201
  self._tksheet_unbind("undo_bindings", "redo_bindings")
3202
+ if binding in ("all", "find"):
3203
+ self.find_enabled = False
3204
+ self._tksheet_unbind("find_bindings")
3205
+ self._tksheet_unbind("find_next_bindings")
3206
+ self._tksheet_unbind("find_previous_bindings")
3207
+ self.close_find_window()
2974
3208
 
2975
3209
  def _tksheet_unbind(self, *keys) -> None:
2976
3210
  for widget in (self, self.RI, self.CH, self.TL):
@@ -3457,26 +3691,42 @@ class MainTable(tk.Canvas):
3457
3691
  if move_synced:
3458
3692
  self.y_move_synced_scrolls(*args, use_scrollbar=True)
3459
3693
 
3460
- def set_xviews(self, *args, move_synced: bool = True, redraw: bool = True) -> None:
3694
+ def set_xviews(
3695
+ self,
3696
+ *args,
3697
+ move_synced: bool = True,
3698
+ redraw: bool = True,
3699
+ ) -> None:
3461
3700
  self.main_table_redraw_grid_and_text(setting_views=True)
3462
- self.update_idletasks()
3701
+ if not self.PAR._startup_complete:
3702
+ self.update_idletasks()
3463
3703
  self.xview(*args)
3464
3704
  if self.show_header:
3465
- self.CH.update_idletasks()
3705
+ if not self.PAR._startup_complete:
3706
+ self.CH.update_idletasks()
3466
3707
  self.CH.xview(*args)
3467
- self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=False)
3708
+ if redraw:
3709
+ self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=False)
3468
3710
  if move_synced:
3469
3711
  self.x_move_synced_scrolls(*args)
3470
3712
  self.fix_views()
3471
3713
 
3472
- def set_yviews(self, *args, move_synced: bool = True, redraw: bool = True) -> None:
3714
+ def set_yviews(
3715
+ self,
3716
+ *args,
3717
+ move_synced: bool = True,
3718
+ redraw: bool = True,
3719
+ ) -> None:
3473
3720
  self.main_table_redraw_grid_and_text(setting_views=True)
3474
- self.update_idletasks()
3721
+ if not self.PAR._startup_complete:
3722
+ self.update_idletasks()
3475
3723
  self.yview(*args)
3476
3724
  if self.show_index:
3477
- self.RI.update_idletasks()
3725
+ if not self.PAR._startup_complete:
3726
+ self.RI.update_idletasks()
3478
3727
  self.RI.yview(*args)
3479
- self.main_table_redraw_grid_and_text(redraw_header=False, redraw_row_index=True)
3728
+ if redraw:
3729
+ self.main_table_redraw_grid_and_text(redraw_header=False, redraw_row_index=True)
3480
3730
  if move_synced:
3481
3731
  self.y_move_synced_scrolls(*args)
3482
3732
  self.fix_views()
@@ -3618,7 +3868,7 @@ class MainTable(tk.Canvas):
3618
3868
  b = self.txt_measure_canvas.bbox(self.txt_measure_canvas_text)
3619
3869
  return b[3] - b[1]
3620
3870
 
3621
- def get_txt_dimensions(self, txt: str, font: None | FontTuple = None) -> int:
3871
+ def get_txt_dimensions(self, txt: str, font: None | FontTuple = None) -> tuple[int, int]:
3622
3872
  self.txt_measure_canvas.itemconfig(
3623
3873
  self.txt_measure_canvas_text,
3624
3874
  text=txt,
@@ -3639,7 +3889,6 @@ class MainTable(tk.Canvas):
3639
3889
  def set_min_column_width(self, width: int) -> None:
3640
3890
  if width:
3641
3891
  self.PAR.ops.min_column_width = width
3642
-
3643
3892
  if self.PAR.ops.min_column_width > self.PAR.ops.max_column_width:
3644
3893
  self.PAR.ops.max_column_width = self.PAR.ops.min_column_width + 20
3645
3894
  if (
@@ -3669,12 +3918,12 @@ class MainTable(tk.Canvas):
3669
3918
  def set_table_font(self, newfont: tuple | None = None, reset_row_positions: bool = False) -> tuple[str, int, str]:
3670
3919
  if newfont:
3671
3920
  if not isinstance(newfont, tuple):
3672
- raise ValueError("Argument must be tuple e.g. " "('Carlito', 12, 'normal')")
3921
+ raise ValueError("Argument must be tuple e.g. ('Carlito', 12, 'normal')")
3673
3922
  if len(newfont) != 3:
3674
3923
  raise ValueError("Argument must be three-tuple")
3675
3924
  if not isinstance(newfont[0], str) or not isinstance(newfont[1], int) or not isinstance(newfont[2], str):
3676
3925
  raise ValueError(
3677
- "Argument must be font, size and 'normal', 'bold' or" "'italic' e.g. ('Carlito',12,'normal')"
3926
+ "Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
3678
3927
  )
3679
3928
  self.PAR.ops.table_font = FontTuple(*newfont)
3680
3929
  self.set_table_font_help()
@@ -3706,7 +3955,7 @@ class MainTable(tk.Canvas):
3706
3955
  raise ValueError("Argument must be three-tuple")
3707
3956
  if not isinstance(newfont[0], str) or not isinstance(newfont[1], int) or not isinstance(newfont[2], str):
3708
3957
  raise ValueError(
3709
- "Argument must be font, size and 'normal', 'bold' or" "'italic' e.g. ('Carlito',12,'normal')"
3958
+ "Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
3710
3959
  )
3711
3960
  self.PAR.ops.header_font = FontTuple(*newfont)
3712
3961
  self.set_header_font_help()
@@ -3737,7 +3986,7 @@ class MainTable(tk.Canvas):
3737
3986
  raise ValueError("Argument must be three-tuple")
3738
3987
  if not isinstance(newfont[0], str) or not isinstance(newfont[1], int) or not isinstance(newfont[2], str):
3739
3988
  raise ValueError(
3740
- "Argument must be font, size and 'normal', 'bold' or" "'italic' e.g. ('Carlito',12,'normal')"
3989
+ "Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
3741
3990
  )
3742
3991
  self.PAR.ops.index_font = FontTuple(*newfont)
3743
3992
  self.set_index_font_help()
@@ -4752,8 +5001,8 @@ class MainTable(tk.Canvas):
4752
5001
  data_ins_col: int,
4753
5002
  displayed_ins_col: int,
4754
5003
  numcols: int,
4755
- columns: list | None = None,
4756
- widths: list | None = None,
5004
+ columns: list[list[object]] | None = None,
5005
+ widths: list[int] | tuple[int] | None = None,
4757
5006
  headers: bool = False,
4758
5007
  ) -> tuple[dict, dict, dict]:
4759
5008
  header_data = {}
@@ -4802,10 +5051,10 @@ class MainTable(tk.Canvas):
4802
5051
  data_ins_row: int,
4803
5052
  displayed_ins_row: int,
4804
5053
  numrows: int,
4805
- rows: list | None = None,
4806
- heights: list | None = None,
5054
+ rows: list[list[object]] | None = None,
5055
+ heights: list[int] | tuple[int] | None = None,
4807
5056
  row_index: bool = False,
4808
- total_data_cols=None,
5057
+ total_data_cols: int | None = None,
4809
5058
  ) -> tuple[dict, dict, dict]:
4810
5059
  index_data = {}
4811
5060
  if isinstance(self._row_index, list):
@@ -5008,7 +5257,7 @@ class MainTable(tk.Canvas):
5008
5257
 
5009
5258
  def display_rows(
5010
5259
  self,
5011
- rows: int | AnyIter | None = None,
5260
+ rows: int | AnyIter[int] | None = None,
5012
5261
  all_rows_displayed: bool | None = None,
5013
5262
  reset_row_positions: bool = True,
5014
5263
  deselect_all: bool = True,
@@ -5037,7 +5286,7 @@ class MainTable(tk.Canvas):
5037
5286
 
5038
5287
  def display_columns(
5039
5288
  self,
5040
- columns: int | AnyIter | None = None,
5289
+ columns: int | AnyIter[int] | None = None,
5041
5290
  all_columns_displayed: bool | None = None,
5042
5291
  reset_col_positions: bool = True,
5043
5292
  deselect_all: bool = True,
@@ -5642,11 +5891,18 @@ class MainTable(tk.Canvas):
5642
5891
  if resized_cols or resized_rows or changed_w:
5643
5892
  self.recreate_all_selection_boxes()
5644
5893
  if changed_w:
5645
- self.update_idletasks()
5646
- self.RI.update_idletasks()
5647
- self.CH.update_idletasks()
5648
- self.TL.update_idletasks()
5894
+ for widget in (self, self.RI, self.CH, self.TL):
5895
+ widget.update_idletasks()
5649
5896
  return False
5897
+ if self.find_window.open:
5898
+ w, h, x, y = self.get_find_window_dimensions_coords(w_width=self.winfo_width())
5899
+ self.coords(self.find_window.canvas_id, x, y)
5900
+ self.itemconfig(
5901
+ self.find_window.canvas_id,
5902
+ width=w,
5903
+ height=h,
5904
+ state="normal",
5905
+ )
5650
5906
  self.hidd_text.update(self.disp_text)
5651
5907
  self.disp_text = {}
5652
5908
  self.hidd_high.update(self.disp_high)
@@ -5677,13 +5933,13 @@ class MainTable(tk.Canvas):
5677
5933
  chain.from_iterable(
5678
5934
  [
5679
5935
  (
5680
- self.canvasx(0) - 1,
5936
+ scrollpos_left - 1,
5681
5937
  self.row_positions[r],
5682
5938
  x_grid_stop,
5683
5939
  self.row_positions[r],
5684
- self.canvasx(0) - 1,
5940
+ scrollpos_left - 1,
5685
5941
  self.row_positions[r],
5686
- self.canvasx(0) - 1,
5942
+ scrollpos_left - 1,
5687
5943
  self.row_positions[r + 1] if len(self.row_positions) - 1 > r else self.row_positions[r],
5688
5944
  )
5689
5945
  for r in range(grid_start_row, grid_end_row)
@@ -6045,56 +6301,35 @@ class MainTable(tk.Canvas):
6045
6301
  box: tuple[int, int, int, int] | None = None,
6046
6302
  run_binding: bool = True,
6047
6303
  ) -> None:
6304
+ def box_created(r: int, c: int, box: SelectionBox) -> bool:
6305
+ r1, c1, r2, c2 = box.coords
6306
+ if r1 <= r and c1 <= c and r2 >= r and c2 >= c:
6307
+ self.create_currently_selected_box(r, c, box.type_, box.fill_iid)
6308
+ if run_binding:
6309
+ self.run_selection_binding(box.type_)
6310
+ return True
6311
+ return False
6312
+
6313
+ # set current to a particular existing selection box
6048
6314
  if isinstance(item, int) and item in self.selection_boxes:
6049
6315
  selection_box = self.selection_boxes[item]
6050
6316
  r1, c1, r2, c2 = selection_box.coords
6051
- if r is None:
6052
- r = r1
6053
- if c is None:
6054
- c = c1
6055
- if r1 <= r and c1 <= c and r2 >= r and c2 >= c:
6056
- self.create_currently_selected_box(
6057
- r,
6058
- c,
6059
- selection_box.type_,
6060
- selection_box.fill_iid,
6061
- )
6062
- if run_binding:
6063
- self.run_selection_binding(selection_box.type_)
6317
+ if box_created(r1 if r is None else r, c1 if c is None else c, selection_box):
6064
6318
  return
6065
- # currently selected is pointed at any selection box with "box" coordinates
6319
+
6320
+ # set current to any existing selection box with coordinates: box
6066
6321
  if isinstance(box, tuple):
6067
- if r is None:
6068
- r = box[0]
6069
- if c is None:
6070
- c = box[1]
6071
6322
  for item, selection_box in self.get_selection_items(reverse=True):
6072
- r1, c1, r2, c2 = selection_box.coords
6073
- if box == (r1, c1, r2, c2) and r1 <= r and c1 <= c and r2 >= r and c2 >= c:
6074
- self.create_currently_selected_box(
6075
- r,
6076
- c,
6077
- selection_box.type_,
6078
- selection_box.fill_iid,
6079
- )
6080
- if run_binding:
6081
- self.run_selection_binding(selection_box.type_)
6082
- return
6083
- # currently selected is just pointed at a coordinate
6084
- # find the top most box there, requires r and c
6085
- if r is not None and c is not None:
6323
+ if box == selection_box.coords:
6324
+ if box_created(box[0] if r is None else r, box[1] if c is None else c, selection_box):
6325
+ return
6326
+
6327
+ # set current to a coordinate, find the top most box there
6328
+ if isinstance(r, int) and isinstance(c, int):
6086
6329
  for item, selection_box in self.get_selection_items(reverse=True):
6087
- r1, c1, r2, c2 = selection_box.coords
6088
- if r1 <= r and c1 <= c and r2 >= r and c2 >= c:
6089
- self.create_currently_selected_box(
6090
- r,
6091
- c,
6092
- selection_box.type_,
6093
- selection_box.fill_iid,
6094
- )
6095
- if run_binding:
6096
- self.run_selection_binding(selection_box.type_)
6330
+ if box_created(r, c, selection_box):
6097
6331
  return
6332
+
6098
6333
  # wasn't provided an item and couldn't find a box at coords so select cell
6099
6334
  if r < len(self.row_positions) - 1 and c < len(self.col_positions) - 1:
6100
6335
  self.select_cell(r, c, redraw=True)
@@ -6215,7 +6450,7 @@ class MainTable(tk.Canvas):
6215
6450
 
6216
6451
  def hide_selection_box(self, item: int | None) -> bool:
6217
6452
  if item is None or item is True or item not in self.selection_boxes:
6218
- return
6453
+ return False
6219
6454
  box = self.selection_boxes.pop(item)
6220
6455
  self.hide_box(box.fill_iid)
6221
6456
  self.hide_box(box.bd_iid)
@@ -6465,50 +6700,30 @@ class MainTable(tk.Canvas):
6465
6700
  def recreate_all_selection_boxes(self) -> None:
6466
6701
  if not self.selected:
6467
6702
  return
6703
+
6468
6704
  modified = False
6705
+ row_limit = len(self.row_positions) - 1
6706
+ col_limit = len(self.col_positions) - 1
6707
+
6469
6708
  for item, box in self.get_selection_items():
6470
6709
  r1, c1, r2, c2 = box.coords
6471
- if not modified:
6472
- modified = (
6473
- r1 >= len(self.row_positions) - 1
6474
- or c1 >= len(self.col_positions) - 1
6475
- or r2 > len(self.row_positions) - 1
6476
- or c2 > len(self.col_positions) - 1
6477
- )
6478
- if r1 >= len(self.row_positions) - 1:
6479
- if len(self.row_positions) > 1:
6480
- r1 = len(self.row_positions) - 2
6481
- else:
6482
- r1 = 0
6483
- if c1 >= len(self.col_positions) - 1:
6484
- if len(self.col_positions) > 1:
6485
- c1 = len(self.col_positions) - 2
6486
- else:
6487
- c1 = 0
6488
- if r2 > len(self.row_positions) - 1:
6489
- r2 = len(self.row_positions) - 1
6490
- if c2 > len(self.col_positions) - 1:
6491
- c2 = len(self.col_positions) - 1
6710
+ # check coordinates
6711
+ r1 = min(r1, row_limit - (1 if row_limit > 0 else 0))
6712
+ c1 = min(c1, col_limit - (1 if col_limit > 0 else 0))
6713
+ r2 = min(r2, row_limit)
6714
+ c2 = min(c2, col_limit)
6715
+
6716
+ modified = modified or (r1 >= row_limit or c1 >= col_limit or r2 > row_limit or c2 > col_limit)
6492
6717
  self.recreate_selection_box(r1, c1, r2, c2, item, run_binding=False)
6493
6718
 
6494
6719
  if self.selected:
6495
- r = self.selected.row
6496
- c = self.selected.column
6497
- if r < len(self.row_positions) - 1 and c < len(self.col_positions) - 1:
6498
- self.set_currently_selected(
6499
- r,
6500
- c,
6501
- item=self.selected.fill_iid,
6502
- run_binding=False,
6503
- )
6720
+ r, c = self.selected.row, self.selected.column
6721
+ if r < row_limit and c < col_limit:
6722
+ self.set_currently_selected(r, c, item=self.selected.fill_iid, run_binding=False)
6504
6723
  else:
6505
6724
  box = self.selection_boxes[self.selected.fill_iid]
6506
- self.set_currently_selected(
6507
- box.coords.from_r,
6508
- box.coords.from_c,
6509
- item=box.fill_iid,
6510
- run_binding=False,
6511
- )
6725
+ self.set_currently_selected(box.coords[0], box.coords[1], item=box.fill_iid, run_binding=False)
6726
+
6512
6727
  if modified:
6513
6728
  self.PAR.emit_event(
6514
6729
  "<<SheetSelect>>",
@@ -6535,23 +6750,17 @@ class MainTable(tk.Canvas):
6535
6750
  return d
6536
6751
 
6537
6752
  def get_selected_min_max(self) -> tuple[int, int, int, int] | tuple[None, None, None, None]:
6538
- min_x = float("inf")
6539
- min_y = float("inf")
6540
- max_x = 0
6541
- max_y = 0
6542
- for item, box in self.get_selection_items():
6753
+ if not self.get_selection_items():
6754
+ return None, None, None, None
6755
+ min_y, min_x = float("inf"), float("inf")
6756
+ max_y, max_x = 0, 0
6757
+
6758
+ for _, box in self.get_selection_items():
6543
6759
  r1, c1, r2, c2 = box.coords
6544
- if r1 < min_y:
6545
- min_y = r1
6546
- if c1 < min_x:
6547
- min_x = c1
6548
- if r2 > max_y:
6549
- max_y = r2
6550
- if c2 > max_x:
6551
- max_x = c2
6552
- if min_x != float("inf") and min_y != float("inf") and max_x > 0 and max_y > 0:
6553
- return min_y, min_x, max_y, max_x
6554
- return None, None, None, None
6760
+ min_y, min_x = min(min_y, r1), min(min_x, c1)
6761
+ max_y, max_x = max(max_y, r2), max(max_x, c2)
6762
+
6763
+ return (min_y, min_x, max_y, max_x) if min_y != float("inf") else (None, None, None, None)
6555
6764
 
6556
6765
  def get_selected_rows(
6557
6766
  self,
@@ -6706,7 +6915,7 @@ class MainTable(tk.Canvas):
6706
6915
  elif self.get_cell_kwargs(datarn, datacn, key="dropdown") or self.get_cell_kwargs(
6707
6916
  datarn, datacn, key="checkbox"
6708
6917
  ):
6709
- if self.event_opens_dropdown_or_checkbox(event):
6918
+ if event_opens_dropdown_or_checkbox(event):
6710
6919
  if self.get_cell_kwargs(datarn, datacn, key="dropdown"):
6711
6920
  self.open_dropdown_window(r, c, event=event)
6712
6921
  elif self.get_cell_kwargs(datarn, datacn, key="checkbox"):
@@ -6714,27 +6923,6 @@ class MainTable(tk.Canvas):
6714
6923
  else:
6715
6924
  self.open_text_editor(event=event, r=r, c=c, dropdown=False)
6716
6925
 
6717
- def event_opens_dropdown_or_checkbox(self, event=None) -> bool:
6718
- if event is None:
6719
- return False
6720
- elif event == "rc":
6721
- return True
6722
- elif (
6723
- (hasattr(event, "keysym") and event.keysym == "Return")
6724
- or (hasattr(event, "keysym") and event.keysym == "F2")
6725
- or (
6726
- event is not None
6727
- and hasattr(event, "keycode")
6728
- and event.keycode == "??"
6729
- and hasattr(event, "num")
6730
- and event.num == 1
6731
- ) # mouseclick
6732
- or (hasattr(event, "keysym") and event.keysym == "BackSpace")
6733
- ):
6734
- return True
6735
- else:
6736
- return False
6737
-
6738
6926
  # displayed indexes
6739
6927
  def get_cell_align(self, r: int, c: int) -> str:
6740
6928
  datarn = self.datarn(r)
@@ -6754,27 +6942,16 @@ class MainTable(tk.Canvas):
6754
6942
  state: str = "normal",
6755
6943
  dropdown: bool = False,
6756
6944
  ) -> bool:
6757
- text = None
6945
+ text = f"{self.get_cell_data(self.datarn(r), self.datacn(c), none_to_empty_str=True)}"
6758
6946
  extra_func_key = "??"
6759
- if event is None or self.event_opens_dropdown_or_checkbox(event):
6760
- if event is not None:
6761
- if hasattr(event, "keysym") and event.keysym == "Return":
6762
- extra_func_key = "Return"
6763
- elif hasattr(event, "keysym") and event.keysym == "F2":
6764
- extra_func_key = "F2"
6765
- if event is not None and (hasattr(event, "keysym") and event.keysym == "BackSpace"):
6766
- extra_func_key = "BackSpace"
6767
- text = ""
6768
- else:
6769
- text = f"{self.get_cell_data(self.datarn(r), self.datacn(c), none_to_empty_str = True)}"
6770
- elif event is not None and (
6771
- (hasattr(event, "char") and event.char.isalpha())
6772
- or (hasattr(event, "char") and event.char.isdigit())
6773
- or (hasattr(event, "char") and event.char in symbols_set)
6774
- ):
6775
- extra_func_key = event.char
6776
- text = event.char
6777
- else:
6947
+ if event_opens_dropdown_or_checkbox(event):
6948
+ if hasattr(event, "keysym") and event.keysym in ("Return", "F2", "BackSpace"):
6949
+ extra_func_key = event.keysym
6950
+ if event.keysym == "BackSpace":
6951
+ text = ""
6952
+ elif event_has_char_key(event):
6953
+ extra_func_key = text = event.char
6954
+ elif event is not None:
6778
6955
  return False
6779
6956
  if self.extra_begin_edit_cell_func:
6780
6957
  try:
@@ -6797,12 +6974,11 @@ class MainTable(tk.Canvas):
6797
6974
  return False
6798
6975
  else:
6799
6976
  text = text if isinstance(text, str) else f"{text}"
6800
- text = "" if text is None else text
6801
6977
  if self.PAR.ops.cell_auto_resize_enabled:
6802
6978
  self.set_cell_size_to_text(r, c, only_if_too_small=True, redraw=True, run_binding=True)
6803
6979
  if self.text_editor.open and (r, c) == self.text_editor.coords:
6804
6980
  self.text_editor.window.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
6805
- return
6981
+ return False
6806
6982
  self.hide_text_editor()
6807
6983
  if not self.see(r=r, c=c, check_cell_visibility=True):
6808
6984
  self.refresh()
@@ -6810,8 +6986,6 @@ class MainTable(tk.Canvas):
6810
6986
  y = self.row_positions[r]
6811
6987
  w = self.col_positions[c + 1] - x + 1
6812
6988
  h = self.row_positions[r + 1] - y + 1
6813
- if text is None:
6814
- text = f"{self.get_cell_data(self.datarn(r), self.datacn(c), none_to_empty_str = True)}"
6815
6989
  kwargs = {
6816
6990
  "menu_kwargs": DotDict(
6817
6991
  {