tksheet 7.4.7__py3-none-any.whl → 7.4.9__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/sheet.py CHANGED
@@ -5,14 +5,20 @@ from bisect import bisect_left
5
5
  from collections import deque
6
6
  from collections.abc import Callable, Generator, Hashable, Iterator, Sequence
7
7
  from contextlib import suppress
8
+ from functools import partial
8
9
  from itertools import accumulate, chain, filterfalse, islice, product, repeat
9
10
  from operator import attrgetter
11
+ from re import IGNORECASE, escape, sub
10
12
  from timeit import default_timer
11
13
  from tkinter import ttk
12
14
  from typing import Any, Literal
13
15
 
14
16
  from .column_headers import ColumnHeaders
15
17
  from .constants import (
18
+ ALL_BINDINGS,
19
+ BINDING_TO_ATTR,
20
+ MODIFIED_BINDINGS,
21
+ SELECT_BINDINGS,
16
22
  USER_OS,
17
23
  align_value_error,
18
24
  backwards_compatibility_keys,
@@ -21,11 +27,13 @@ from .constants import (
21
27
  rc_binding,
22
28
  scrollbar_options_keys,
23
29
  )
30
+ from .find_window import replacer
24
31
  from .functions import (
25
32
  add_highlight,
26
33
  add_to_options,
27
34
  alpha2idx,
28
35
  bisect_in,
36
+ box_gen_coords,
29
37
  consecutive_ranges,
30
38
  convert_align,
31
39
  del_from_options,
@@ -42,6 +50,7 @@ from .functions import (
42
50
  idx_param_to_int,
43
51
  is_iterable,
44
52
  key_to_span,
53
+ mod_event_val,
45
54
  new_tk_event,
46
55
  num2alpha,
47
56
  pop_positions,
@@ -51,6 +60,7 @@ from .functions import (
51
60
  span_ranges,
52
61
  stored_event_dict,
53
62
  tksheet_type_error,
63
+ try_binding,
54
64
  unpack,
55
65
  )
56
66
  from .main_table import MainTable
@@ -293,6 +303,7 @@ class Sheet(tk.Frame):
293
303
  row_height: str | int | None = None,
294
304
  row_index_width: int | None = None,
295
305
  expand_sheet_if_paste_too_big: bool | None = None,
306
+ **kwargs,
296
307
  ) -> None:
297
308
  super().__init__(
298
309
  parent,
@@ -604,97 +615,10 @@ class Sheet(tk.Frame):
604
615
  # Bindings and Functionality
605
616
 
606
617
  def enable_bindings(self, *bindings: Binding) -> Sheet:
607
- """
608
- List of available bindings:
609
- - "all"
610
- - "single_select"
611
- - "toggle_select"
612
- - "drag_select"
613
- - "select_all"
614
- - "column_drag_and_drop" / "move_columns"
615
- - "row_drag_and_drop" / "move_rows"
616
- - "column_select"
617
- - "row_select"
618
- - "column_width_resize"
619
- - "double_click_column_resize"
620
- - "row_width_resize"
621
- - "column_height_resize"
622
- - "arrowkeys" # all arrowkeys including page up and down
623
- - "up"
624
- - "down"
625
- - "left"
626
- - "right"
627
- - "prior" # page up
628
- - "next" # page down
629
- - "row_height_resize"
630
- - "double_click_row_resize"
631
- - "right_click_popup_menu" / "rc_popup_menu" / "rc_menu"
632
- - "rc_select"
633
- - "rc_insert_column"
634
- - "rc_delete_column"
635
- - "rc_insert_row"
636
- - "rc_delete_row"
637
- - "sort_cells"
638
- - "sort_row"
639
- - "sort_column" / "sort_col"
640
- - "sort_rows"
641
- - "sort_columns" / "sort_cols"
642
- - "ctrl_click_select" / "ctrl_select"
643
- - "copy"
644
- - "cut"
645
- - "paste"
646
- - "delete"
647
- - "undo"
648
- - "find"
649
- - "edit_cell"
650
- - "edit_header"
651
- - "edit_index"
652
- """
653
618
  self.MT.enable_bindings(bindings)
654
619
  return self
655
620
 
656
621
  def disable_bindings(self, *bindings: Binding) -> Sheet:
657
- """
658
- List of available bindings:
659
- - "all"
660
- - "single_select"
661
- - "toggle_select"
662
- - "drag_select"
663
- - "select_all"
664
- - "column_drag_and_drop" / "move_columns"
665
- - "row_drag_and_drop" / "move_rows"
666
- - "column_select"
667
- - "row_select"
668
- - "column_width_resize"
669
- - "double_click_column_resize"
670
- - "row_width_resize"
671
- - "column_height_resize"
672
- - "arrowkeys" # all arrowkeys including page up and down
673
- - "up"
674
- - "down"
675
- - "left"
676
- - "right"
677
- - "prior" # page up
678
- - "next" # page down
679
- - "row_height_resize"
680
- - "double_click_row_resize"
681
- - "right_click_popup_menu" / "rc_popup_menu" / "rc_menu"
682
- - "rc_select"
683
- - "rc_insert_column"
684
- - "rc_delete_column"
685
- - "rc_insert_row"
686
- - "rc_delete_row"
687
- - "ctrl_click_select" / "ctrl_select"
688
- - "copy"
689
- - "cut"
690
- - "paste"
691
- - "delete"
692
- - "undo"
693
- - "find"
694
- - "edit_cell"
695
- - "edit_header"
696
- - "edit_index"
697
- """
698
622
  self.MT.disable_bindings(bindings)
699
623
  return self
700
624
 
@@ -703,76 +627,15 @@ class Sheet(tk.Frame):
703
627
  bindings: ExtraBinding | Sequence[ExtraBinding] | None = None,
704
628
  func: Callable | None = None,
705
629
  ) -> Sheet:
706
- """
707
- List of available bindings:
708
- - "begin_sort_cells"
709
- - "sort_cells", "end_sort_cells"
710
- - "begin_sort_rows"
711
- - "sort_rows", "end_sort_rows"
712
- - "begin_sort_columns"
713
- - "sort_columns", "end_sort_columns"
714
- - "begin_copy", "begin_ctrl_c"
715
- - "ctrl_c", "end_copy", "end_ctrl_c", "copy"
716
- - "begin_cut", "begin_ctrl_x"
717
- - "ctrl_x", "end_cut", "end_ctrl_x", "cut"
718
- - "begin_paste", "begin_ctrl_v"
719
- - "ctrl_v", "end_paste", "end_ctrl_v", "paste"
720
- - "begin_undo", "begin_ctrl_z"
721
- - "ctrl_z", "end_undo", "end_ctrl_z", "undo"
722
- - "begin_delete_key", "begin_delete"
723
- - "delete_key", "end_delete", "end_delete_key", "delete"
724
- - "begin_edit_cell", "begin_edit_table"
725
- - "end_edit_cell", "edit_cell", "edit_table"
726
- - "begin_edit_header"
727
- - "end_edit_header", "edit_header"
728
- - "begin_edit_index"
729
- - "end_edit_index", "edit_index"
730
- - "begin_row_index_drag_drop", "begin_move_rows"
731
- - "row_index_drag_drop", "move_rows", "end_move_rows", "end_row_index_drag_drop"
732
- - "begin_column_header_drag_drop", "begin_move_columns"
733
- - "column_header_drag_drop", "move_columns", "end_move_columns", "end_column_header_drag_drop"
734
- - "begin_rc_delete_row", "begin_delete_rows"
735
- - "rc_delete_row", "end_rc_delete_row", "end_delete_rows", "delete_rows"
736
- - "begin_rc_delete_column", "begin_delete_columns"
737
- - "rc_delete_column", "end_rc_delete_column","end_delete_columns", "delete_columns"
738
- - "begin_rc_insert_column", "begin_insert_column", "begin_insert_columns", "begin_add_column",
739
- "begin_rc_add_column", "begin_add_columns"
740
- - "rc_insert_column", "end_rc_insert_column", "end_insert_column", "end_insert_columns", "rc_add_column",
741
- "end_rc_add_column", "end_add_column", "end_add_columns", "add_columns"
742
- - "begin_rc_insert_row", "begin_insert_row", "begin_insert_rows", "begin_rc_add_row", "begin_add_row",
743
- "begin_add_rows"
744
- - "rc_insert_row", "end_rc_insert_row", "end_insert_row", "end_insert_rows", "rc_add_row", "end_rc_add_row",
745
- "end_add_row", "end_add_rows", "add_rows"
746
- - "row_height_resize"
747
- - "column_width_resize"
748
- - "cell_select"
749
- - "select_all"
750
- - "row_select"
751
- - "column_select"
752
- - "drag_select_cells"
753
- - "drag_select_rows"
754
- - "drag_select_columns"
755
- - "shift_cell_select"
756
- - "shift_row_select"
757
- - "shift_column_select"
758
- - "ctrl_cell_select"
759
- - "ctrl_row_select"
760
- - "ctrl_column_select"
761
- - "deselect"
762
- - "all_select_events", "select", "selectevents", "select_events"
763
- - "all_modified_events", "sheetmodified", "sheet_modified", "modified_events", "modified"
764
- - "bind_all"
765
- - "unbind_all"
766
- """
767
630
  # bindings is None, unbind all
768
631
  if bindings is None:
769
632
  bindings = "all"
770
633
  # bindings is str, func arg is None or Callable
771
634
  if isinstance(bindings, str):
772
- iterable = [(bindings, func)]
635
+ iterable = ((bindings, func),)
773
636
  # bindings is list or tuple of strings, func arg is None or Callable
774
637
  elif is_iterable(bindings) and isinstance(bindings[0], str):
775
- iterable = [(b, func) for b in bindings]
638
+ iterable = ((b, func) for b in bindings)
776
639
  # bindings is a list or tuple of two tuples or lists
777
640
  # in this case the func arg is ignored
778
641
  # e.g. [(binding, function), (binding, function), ...]
@@ -781,333 +644,22 @@ class Sheet(tk.Frame):
781
644
 
782
645
  for b, f in iterable:
783
646
  b = b.lower()
784
-
785
647
  if f is not None and b in emitted_events:
786
648
  self.bind(b, f)
787
-
788
- if b in (
789
- "all",
790
- "bind_all",
791
- "unbind_all",
792
- ):
793
- self.MT.extra_begin_sort_cells_func = f
794
- self.CH.ch_extra_begin_sort_rows_func = f
795
- self.RI.ri_extra_begin_sort_cols_func = f
796
- self.MT.extra_begin_ctrl_c_func = f
797
- self.MT.extra_begin_ctrl_x_func = f
798
- self.MT.extra_begin_ctrl_v_func = f
799
- self.MT.extra_begin_ctrl_z_func = f
800
- self.MT.extra_begin_delete_key_func = f
801
- self.RI.ri_extra_begin_drag_drop_func = f
802
- self.CH.ch_extra_begin_drag_drop_func = f
803
- self.MT.extra_begin_del_rows_rc_func = f
804
- self.MT.extra_begin_del_cols_rc_func = f
805
- self.MT.extra_begin_insert_cols_rc_func = f
806
- self.MT.extra_begin_insert_rows_rc_func = f
807
- self.MT.extra_begin_edit_cell_func = f
808
- self.CH.extra_begin_edit_cell_func = f
809
- self.RI.extra_begin_edit_cell_func = f
810
- self.CH.column_width_resize_func = f
811
- self.RI.row_height_resize_func = f
812
-
813
- if b in (
814
- "all",
815
- "bind_all",
816
- "unbind_all",
817
- "all_select_events",
818
- "select",
819
- "selectevents",
820
- "select_events",
821
- ):
822
- self.MT.selection_binding_func = f
823
- self.MT.select_all_binding_func = f
824
- self.RI.selection_binding_func = f
825
- self.CH.selection_binding_func = f
826
- self.MT.drag_selection_binding_func = f
827
- self.RI.drag_selection_binding_func = f
828
- self.CH.drag_selection_binding_func = f
829
- self.MT.shift_selection_binding_func = f
830
- self.RI.shift_selection_binding_func = f
831
- self.CH.shift_selection_binding_func = f
832
- self.MT.ctrl_selection_binding_func = f
833
- self.RI.ctrl_selection_binding_func = f
834
- self.CH.ctrl_selection_binding_func = f
835
- self.MT.deselection_binding_func = f
836
-
837
- if b in (
838
- "all",
839
- "bind_all",
840
- "unbind_all",
841
- "all_modified_events",
842
- "sheetmodified",
843
- "sheet_modified",
844
- "modified_events",
845
- "modified",
846
- ):
847
- self.MT.extra_end_sort_cells_func = f
848
- self.CH.ch_extra_end_sort_rows_func = f
849
- self.RI.ri_extra_end_sort_cols_func = f
850
- self.MT.extra_end_ctrl_c_func = f
851
- self.MT.extra_end_ctrl_x_func = f
852
- self.MT.extra_end_ctrl_v_func = f
853
- self.MT.extra_end_ctrl_z_func = f
854
- self.MT.extra_end_delete_key_func = f
855
- self.RI.ri_extra_end_drag_drop_func = f
856
- self.CH.ch_extra_end_drag_drop_func = f
857
- self.MT.extra_end_del_rows_rc_func = f
858
- self.MT.extra_end_del_cols_rc_func = f
859
- self.MT.extra_end_insert_cols_rc_func = f
860
- self.MT.extra_end_insert_rows_rc_func = f
861
- self.MT.extra_end_edit_cell_func = f
862
- self.CH.extra_end_edit_cell_func = f
863
- self.RI.extra_end_edit_cell_func = f
864
-
865
- if b in ("begin_sort_cells",):
866
- self.MT.extra_begin_sort_cells_func = f
867
-
868
- if b in ("sort_cells", "end_sort_cells"):
869
- self.MT.extra_end_sort_cells_func = f
870
-
871
- if b in ("begin_sort_rows",):
872
- self.CH.ch_extra_begin_sort_rows_func = f
873
-
874
- if b in ("sort_rows", "end_sort_rows"):
875
- self.CH.ch_extra_end_sort_rows_func = f
876
-
877
- if b in ("begin_sort_columns",):
878
- self.RI.ri_extra_begin_sort_cols_func = f
879
-
880
- if b in ("sort_columns", "end_sort_columns"):
881
- self.RI.ri_extra_end_sort_cols_func = f
882
-
883
- if b in (
884
- "begin_copy",
885
- "begin_ctrl_c",
886
- ):
887
- self.MT.extra_begin_ctrl_c_func = f
888
- if b in (
889
- "ctrl_c",
890
- "end_copy",
891
- "end_ctrl_c",
892
- "copy",
893
- ):
894
- self.MT.extra_end_ctrl_c_func = f
895
-
896
- if b in (
897
- "begin_cut",
898
- "begin_ctrl_x",
899
- ):
900
- self.MT.extra_begin_ctrl_x_func = f
901
- if b in (
902
- "ctrl_x",
903
- "end_cut",
904
- "end_ctrl_x",
905
- "cut",
906
- ):
907
- self.MT.extra_end_ctrl_x_func = f
908
-
909
- if b in (
910
- "begin_paste",
911
- "begin_ctrl_v",
912
- ):
913
- self.MT.extra_begin_ctrl_v_func = f
914
- if b in (
915
- "ctrl_v",
916
- "end_paste",
917
- "end_ctrl_v",
918
- "paste",
919
- ):
920
- self.MT.extra_end_ctrl_v_func = f
921
-
922
- if b in (
923
- "begin_undo",
924
- "begin_ctrl_z",
925
- ):
926
- self.MT.extra_begin_ctrl_z_func = f
927
- if b in (
928
- "ctrl_z",
929
- "end_undo",
930
- "end_ctrl_z",
931
- "undo",
932
- ):
933
- self.MT.extra_end_ctrl_z_func = f
934
-
935
- if b in (
936
- "begin_delete_key",
937
- "begin_delete",
938
- ):
939
- self.MT.extra_begin_delete_key_func = f
940
- if b in (
941
- "delete_key",
942
- "end_delete",
943
- "end_delete_key",
944
- "delete",
945
- ):
946
- self.MT.extra_end_delete_key_func = f
947
-
948
- if b in (
949
- "begin_edit_cell",
950
- "begin_edit_table",
951
- ):
952
- self.MT.extra_begin_edit_cell_func = f
953
- if b in (
954
- "end_edit_cell",
955
- "edit_cell",
956
- "edit_table",
957
- ):
958
- self.MT.extra_end_edit_cell_func = f
959
-
960
- if b == "begin_edit_header":
961
- self.CH.extra_begin_edit_cell_func = f
962
- if b in (
963
- "end_edit_header",
964
- "edit_header",
965
- ):
966
- self.CH.extra_end_edit_cell_func = f
967
-
968
- if b == "begin_edit_index":
969
- self.RI.extra_begin_edit_cell_func = f
970
- if b in (
971
- "end_edit_index",
972
- "edit_index",
973
- ):
974
- self.RI.extra_end_edit_cell_func = f
975
-
976
- if b in (
977
- "begin_row_index_drag_drop",
978
- "begin_move_rows",
979
- ):
980
- self.RI.ri_extra_begin_drag_drop_func = f
981
- if b in (
982
- "row_index_drag_drop",
983
- "move_rows",
984
- "end_move_rows",
985
- "end_row_index_drag_drop",
986
- ):
987
- self.RI.ri_extra_end_drag_drop_func = f
988
-
989
- if b in (
990
- "begin_column_header_drag_drop",
991
- "begin_move_columns",
992
- ):
993
- self.CH.ch_extra_begin_drag_drop_func = f
994
- if b in (
995
- "column_header_drag_drop",
996
- "move_columns",
997
- "end_move_columns",
998
- "end_column_header_drag_drop",
999
- ):
1000
- self.CH.ch_extra_end_drag_drop_func = f
1001
-
1002
- if b in (
1003
- "begin_rc_delete_row",
1004
- "begin_delete_rows",
1005
- ):
1006
- self.MT.extra_begin_del_rows_rc_func = f
1007
- if b in (
1008
- "rc_delete_row",
1009
- "end_rc_delete_row",
1010
- "end_delete_rows",
1011
- "delete_rows",
1012
- ):
1013
- self.MT.extra_end_del_rows_rc_func = f
1014
-
1015
- if b in (
1016
- "begin_rc_delete_column",
1017
- "begin_delete_columns",
1018
- ):
1019
- self.MT.extra_begin_del_cols_rc_func = f
1020
- if b in (
1021
- "rc_delete_column",
1022
- "end_rc_delete_column",
1023
- "end_delete_columns",
1024
- "delete_columns",
1025
- ):
1026
- self.MT.extra_end_del_cols_rc_func = f
1027
-
1028
- if b in (
1029
- "begin_rc_insert_column",
1030
- "begin_insert_column",
1031
- "begin_insert_columns",
1032
- "begin_add_column",
1033
- "begin_rc_add_column",
1034
- "begin_add_columns",
1035
- ):
1036
- self.MT.extra_begin_insert_cols_rc_func = f
1037
- if b in (
1038
- "rc_insert_column",
1039
- "end_rc_insert_column",
1040
- "end_insert_column",
1041
- "end_insert_columns",
1042
- "rc_add_column",
1043
- "end_rc_add_column",
1044
- "end_add_column",
1045
- "end_add_columns",
1046
- "add_columns",
1047
- ):
1048
- self.MT.extra_end_insert_cols_rc_func = f
1049
-
1050
- if b in (
1051
- "begin_rc_insert_row",
1052
- "begin_insert_row",
1053
- "begin_insert_rows",
1054
- "begin_rc_add_row",
1055
- "begin_add_row",
1056
- "begin_add_rows",
1057
- ):
1058
- self.MT.extra_begin_insert_rows_rc_func = f
1059
- if b in (
1060
- "rc_insert_row",
1061
- "end_rc_insert_row",
1062
- "end_insert_row",
1063
- "end_insert_rows",
1064
- "rc_add_row",
1065
- "end_rc_add_row",
1066
- "end_add_row",
1067
- "end_add_rows",
1068
- "add_rows",
1069
- ):
1070
- self.MT.extra_end_insert_rows_rc_func = f
1071
-
1072
- if b == "column_width_resize":
1073
- self.CH.column_width_resize_func = f
1074
- if b == "row_height_resize":
1075
- self.RI.row_height_resize_func = f
1076
-
1077
- if b == "cell_select":
1078
- self.MT.selection_binding_func = f
1079
- if b in (
1080
- "select_all",
1081
- "ctrl_a",
1082
- ):
1083
- self.MT.select_all_binding_func = f
1084
- if b == "row_select":
1085
- self.RI.selection_binding_func = f
1086
- if b in (
1087
- "col_select",
1088
- "column_select",
1089
- ):
1090
- self.CH.selection_binding_func = f
1091
- if b == "drag_select_cells":
1092
- self.MT.drag_selection_binding_func = f
1093
- if b == "drag_select_rows":
1094
- self.RI.drag_selection_binding_func = f
1095
- if b == "drag_select_columns":
1096
- self.CH.drag_selection_binding_func = f
1097
- if b == "shift_cell_select":
1098
- self.MT.shift_selection_binding_func = f
1099
- if b == "shift_row_select":
1100
- self.RI.shift_selection_binding_func = f
1101
- if b == "shift_column_select":
1102
- self.CH.shift_selection_binding_func = f
1103
- if b == "ctrl_cell_select":
1104
- self.MT.ctrl_selection_binding_func = f
1105
- if b == "ctrl_row_select":
1106
- self.RI.ctrl_selection_binding_func = f
1107
- if b == "ctrl_column_select":
1108
- self.CH.ctrl_selection_binding_func = f
1109
- if b == "deselect":
1110
- self.MT.deselection_binding_func = f
649
+ # Handle group bindings
650
+ if b in ("all", "bind_all", "unbind_all"):
651
+ for component, attr in ALL_BINDINGS:
652
+ setattr(getattr(self, component), attr, f)
653
+ elif b in ("all_select_events", "select", "selectevents", "select_events"):
654
+ for component, attr in SELECT_BINDINGS:
655
+ setattr(getattr(self, component), attr, f)
656
+ elif b in ("all_modified_events", "sheetmodified", "sheet_modified", "modified_events", "modified"):
657
+ for component, attr in MODIFIED_BINDINGS:
658
+ setattr(getattr(self, component), attr, f)
659
+ # Handle individual bindings
660
+ elif b in BINDING_TO_ATTR:
661
+ component, attr = BINDING_TO_ATTR[b]
662
+ setattr(getattr(self, component), attr, f)
1111
663
  return self
1112
664
 
1113
665
  def bind(
@@ -1214,9 +766,17 @@ class Sheet(tk.Frame):
1214
766
  return self
1215
767
 
1216
768
  def edit_validation(self, func: Callable | None = None) -> Sheet:
769
+ if not isinstance(func, (Callable, None)):
770
+ raise ValueError("Argument must be either Callable or None.")
1217
771
  self.MT.edit_validation_func = func
1218
772
  return self
1219
773
 
774
+ def bulk_table_edit_validation(self, func: Callable | None = None) -> Sheet:
775
+ if not isinstance(func, (Callable, None)):
776
+ raise ValueError("Argument must be either Callable or None.")
777
+ self.MT.bulk_table_edit_validation_func = func
778
+ return self
779
+
1220
780
  def popup_menu_add_command(
1221
781
  self,
1222
782
  label: str,
@@ -1488,7 +1048,7 @@ class Sheet(tk.Frame):
1488
1048
  def get_data(self, *key: CreateSpanTypes) -> Any:
1489
1049
  """
1490
1050
  e.g. retrieves entire table as pandas dataframe
1491
- sheet["A1"].expand().options(pandas.DataFrame).data
1051
+ sheet["A1"].expand().options(convert=pandas.DataFrame).data
1492
1052
 
1493
1053
  must deal with
1494
1054
  - format
@@ -1547,56 +1107,48 @@ class Sheet(tk.Frame):
1547
1107
  """
1548
1108
  span = self.span_from_key(*key)
1549
1109
  rows, cols = self.ranges_from_span(span)
1550
- tdisp, idisp, hdisp = span.tdisp, span.idisp, span.hdisp
1551
1110
  table, index, header = span.table, span.index, span.header
1552
1111
  fmt_kw = span.kwargs if span.type_ == "format" and span.kwargs else None
1553
- quick_tdata, quick_idata, quick_hdata = self.MT.get_cell_data, self.RI.get_cell_data, self.CH.get_cell_data
1112
+ t_data = partial(self.MT.get_cell_data, get_displayed=True) if span.tdisp else self.MT.get_cell_data
1113
+ i_data = self.RI.cell_str if span.idisp else self.RI.get_cell_data
1114
+ h_data = self.CH.cell_str if span.hdisp else self.CH.get_cell_data
1554
1115
  res = []
1555
1116
  if span.transposed:
1117
+ # Index row (first row when transposed)
1556
1118
  if index:
1557
- if index and header:
1558
- if table:
1559
- res.append([""] + [quick_idata(r, get_displayed=idisp) for r in rows])
1560
- else:
1561
- res.append([quick_idata(r, get_displayed=idisp) for r in rows])
1562
- else:
1563
- res.append([quick_idata(r, get_displayed=idisp) for r in rows])
1119
+ index_row = [""] if header and table else []
1120
+ index_row.extend(i_data(r) for r in rows)
1121
+ res.append(index_row)
1122
+ # Header and/or table data as columns
1564
1123
  if header:
1565
- if table:
1566
- res.extend(
1567
- [quick_hdata(c, get_displayed=hdisp)]
1568
- + [quick_tdata(r, c, get_displayed=tdisp, fmt_kw=fmt_kw) for r in rows]
1569
- for c in cols
1570
- )
1571
- else:
1572
- res.extend([quick_hdata(c, get_displayed=hdisp)] for c in cols)
1124
+ for c in cols:
1125
+ col = [h_data(c)]
1126
+ if table:
1127
+ col.extend(t_data(r, c, fmt_kw=fmt_kw) for r in rows)
1128
+ res.append(col)
1573
1129
  elif table:
1574
- res.extend([quick_tdata(r, c, get_displayed=tdisp, fmt_kw=fmt_kw) for r in rows] for c in cols)
1575
- elif not span.transposed:
1130
+ res.extend([t_data(r, c, fmt_kw=fmt_kw) for r in rows] for c in cols)
1131
+ else:
1132
+ # Header row
1576
1133
  if header:
1577
- if header and index:
1578
- if table:
1579
- res.append([""] + [quick_hdata(c, get_displayed=hdisp) for c in cols])
1580
- else:
1581
- res.append([quick_hdata(c, get_displayed=hdisp) for c in cols])
1582
- else:
1583
- res.append([quick_hdata(c, get_displayed=hdisp) for c in cols])
1134
+ header_row = [""] if index and table else []
1135
+ header_row.extend(h_data(c) for c in cols)
1136
+ res.append(header_row)
1137
+ # Index and/or table data as rows
1584
1138
  if index:
1585
- if table:
1586
- res.extend(
1587
- [quick_idata(r, get_displayed=idisp)]
1588
- + [quick_tdata(r, c, get_displayed=tdisp, fmt_kw=fmt_kw) for c in cols]
1589
- for r in rows
1590
- )
1591
- else:
1592
- res.extend([quick_idata(r, get_displayed=idisp)] for r in rows)
1139
+ for r in rows:
1140
+ row = [i_data(r)]
1141
+ if table:
1142
+ row.extend(t_data(r, c, fmt_kw=fmt_kw) for c in cols)
1143
+ res.append(row)
1593
1144
  elif table:
1594
- res.extend([quick_tdata(r, c, get_displayed=tdisp, fmt_kw=fmt_kw) for c in cols] for r in rows)
1145
+ res.extend([t_data(r, c, fmt_kw=fmt_kw) for c in cols] for r in rows)
1146
+
1595
1147
  if not span.ndim:
1596
1148
  # it's a cell
1597
1149
  if len(res) == 1 and len(res[0]) == 1:
1598
1150
  res = res[0][0]
1599
- # it's a single list
1151
+ # it's a single sublist
1600
1152
  elif len(res) == 1:
1601
1153
  res = res[0]
1602
1154
  # retrieving a list of index cells or
@@ -1608,11 +1160,12 @@ class Sheet(tk.Frame):
1608
1160
  elif span.ndim == 1:
1609
1161
  # flatten sublists
1610
1162
  res = res[0] if len(res) == 1 and len(res[0]) == 1 else list(chain.from_iterable(res))
1611
- # if span.ndim == 2 res keeps its current
1612
- # dimensions as a list of lists
1613
- if span.convert is not None:
1163
+ # if span.ndim == 2 res keeps its current dimensions as a list of lists
1164
+
1165
+ if span.convert is None:
1166
+ return res
1167
+ else:
1614
1168
  return span.convert(res)
1615
- return res
1616
1169
 
1617
1170
  def get_total_rows(self, include_index: bool = False) -> int:
1618
1171
  return self.MT.total_data_rows(include_index=include_index)
@@ -2671,6 +2224,90 @@ class Sheet(tk.Frame):
2671
2224
  ) -> EventDataDict:
2672
2225
  return self.RI._sort_columns_by_row(row=row, reverse=reverse, key=key, undo=undo)
2673
2226
 
2227
+ # Find and Replace
2228
+
2229
+ @property
2230
+ def find_open(self) -> bool:
2231
+ return self.MT.find_window.open
2232
+
2233
+ def open_find(self, focus: bool = False) -> Sheet:
2234
+ self.MT.open_find_window(focus=focus)
2235
+ return self
2236
+
2237
+ def close_find(self) -> Sheet:
2238
+ self.MT.close_find_window()
2239
+ return self
2240
+
2241
+ def next_match(self, within: bool | None = None, find: str | None = None) -> Sheet:
2242
+ self.MT.find_next(within=within, find=find)
2243
+ return self
2244
+
2245
+ def prev_match(self, within: bool | None = None, find: str | None = None) -> Sheet:
2246
+ self.MT.find_previous(within=within, find=find)
2247
+ return self
2248
+
2249
+ def replace_all(self, mapping: dict[str, str], within: bool = False) -> EventDataDict:
2250
+ event_data = self.MT.new_event_dict("edit_table", boxes=self.MT.get_boxes())
2251
+ if within:
2252
+ iterable = chain.from_iterable(
2253
+ (
2254
+ box_gen_coords(
2255
+ *box.coords,
2256
+ start_r=box.coords.from_r,
2257
+ start_c=box.coords.from_c,
2258
+ reverse=False,
2259
+ all_rows_displayed=self.MT.all_rows_displayed,
2260
+ all_cols_displayed=self.MT.all_columns_displayed,
2261
+ displayed_rows=self.MT.displayed_rows,
2262
+ displayed_cols=self.MT.displayed_columns,
2263
+ )
2264
+ for box in self.MT.selection_boxes.values()
2265
+ )
2266
+ )
2267
+ else:
2268
+ iterable = box_gen_coords(
2269
+ from_r=0,
2270
+ from_c=0,
2271
+ upto_r=self.MT.total_data_rows(include_index=False),
2272
+ upto_c=self.MT.total_data_cols(include_header=False),
2273
+ start_r=0,
2274
+ start_c=0,
2275
+ reverse=False,
2276
+ )
2277
+ for r, c in iterable:
2278
+ for find, replace in mapping.items():
2279
+ m = self.MT.find_match(find, r, c)
2280
+ if (
2281
+ m
2282
+ and not within
2283
+ or (
2284
+ within
2285
+ and (self.MT.all_rows_displayed or bisect_in(self.MT.displayed_rows, r))
2286
+ and (self.MT.all_columns_displayed or bisect_in(self.MT.displayed_columns, c))
2287
+ )
2288
+ ):
2289
+ current = f"{self.MT.get_cell_data(r, c, True)}"
2290
+ new = sub(escape(find), replacer(find, replace, current), current, flags=IGNORECASE)
2291
+ if not self.MT.edit_validation_func or (
2292
+ self.MT.edit_validation_func
2293
+ and (new := self.MT.edit_validation_func(mod_event_val(event_data, new, (r, c)))) is not None
2294
+ ):
2295
+ event_data = self.MT.event_data_set_cell(
2296
+ r,
2297
+ c,
2298
+ new,
2299
+ event_data,
2300
+ )
2301
+ event_data = self.MT.bulk_edit_validation(event_data)
2302
+ if event_data["cells"]["table"]:
2303
+ self.MT.refresh()
2304
+ if self.MT.undo_enabled:
2305
+ self.MT.undo_stack.append(stored_event_dict(event_data))
2306
+ try_binding(self.MT.extra_end_replace_all_func, event_data)
2307
+ self.MT.sheet_modified(event_data)
2308
+ self.emit_event("<<SheetModified>>", event_data)
2309
+ return event_data
2310
+
2674
2311
  # Highlighting Cells
2675
2312
 
2676
2313
  def highlight(
@@ -2889,13 +2526,13 @@ class Sheet(tk.Frame):
2889
2526
  self.del_index_cell_options_dropdown_and_checkbox(r)
2890
2527
  add_to_options(self.RI.cell_options, r, "checkbox", d)
2891
2528
  if edit_data:
2892
- set_idata(r, checked if isinstance(checked, bool) else force_bool(self.get_index_data(r)))
2529
+ set_idata(r, checked if isinstance(checked, bool) else force_bool(self.RI.get_cell_data(r)))
2893
2530
  if header:
2894
2531
  for c in cols:
2895
2532
  self.del_header_cell_options_dropdown_and_checkbox(c)
2896
2533
  add_to_options(self.CH.cell_options, c, "checkbox", d)
2897
2534
  if edit_data:
2898
- set_hdata(c, checked if isinstance(checked, bool) else force_bool(self.get_header_data(c)))
2535
+ set_hdata(c, checked if isinstance(checked, bool) else force_bool(self.CH.get_cell_data(c)))
2899
2536
  if table:
2900
2537
  if span.kind == "cell":
2901
2538
  for r in rows:
@@ -4451,6 +4088,10 @@ class Sheet(tk.Frame):
4451
4088
 
4452
4089
  # Cell Text Editor
4453
4090
 
4091
+ def next_cell(self, r: int, c: int, key: Literal["Return", "Tab", "??"]) -> Sheet:
4092
+ self.MT.go_to_next_cell(r, c, key)
4093
+ return self
4094
+
4454
4095
  # works on currently selected box
4455
4096
  def open_cell(self, ignore_existing_editor: bool = True) -> Sheet:
4456
4097
  self.MT.open_cell(event=GeneratedMouseEvent(), ignore_existing_editor=ignore_existing_editor)
@@ -4533,13 +4174,16 @@ class Sheet(tk.Frame):
4533
4174
  # Sheet Options and Other Functions
4534
4175
 
4535
4176
  def set_options(self, redraw: bool = True, **kwargs) -> Sheet:
4177
+ enabled = tuple(self.MT.enabled_bindings)
4536
4178
  for k, v in kwargs.items():
4537
4179
  if k in self.ops and v != self.ops[k]:
4538
4180
  if k.endswith("bindings"):
4539
- self.MT._disable_binding(k.split("_")[0])
4181
+ for b in enabled:
4182
+ self.MT._disable_binding(b)
4540
4183
  self.ops[k] = v
4541
4184
  if k.endswith("bindings"):
4542
- self.MT._enable_binding(k.split("_")[0])
4185
+ for b in enabled:
4186
+ self.MT._enable_binding(b)
4543
4187
  if "name" in kwargs:
4544
4188
  self.name = kwargs["name"]
4545
4189
  if "min_column_width" in kwargs:
@@ -5420,9 +5064,7 @@ class Sheet(tk.Frame):
5420
5064
  - Unlike the ttk treeview 'see' function
5421
5065
  this function does **NOT** scroll to the item
5422
5066
  """
5423
- if item not in self.RI.tree:
5424
- raise ValueError(f"Item '{item}' does not exist.")
5425
- if self.RI.tree[item].parent:
5067
+ if not self.item_displayed(item) and self.RI.tree[item].parent:
5426
5068
  self.show_rows(
5427
5069
  rows=self._tree_open(list(self.RI.get_iid_ancestors(item))),
5428
5070
  redraw=False,
@@ -5434,8 +5076,6 @@ class Sheet(tk.Frame):
5434
5076
  """
5435
5077
  Scrolls to an item and ensures that it is displayed
5436
5078
  """
5437
- if item not in self.RI.tree:
5438
- raise ValueError(f"Item '{item}' does not exist.")
5439
5079
  self.display_item(item, redraw=False)
5440
5080
  self.see(
5441
5081
  row=bisect_left(self.MT.displayed_rows, self.RI.tree_rns[item]),
@@ -5656,7 +5296,10 @@ class Sheet(tk.Frame):
5656
5296
  # ########## OLD FUNCTIONS ##########
5657
5297
 
5658
5298
  def get_cell_data(self, r: int, c: int, get_displayed: bool = False) -> Any:
5659
- return self.MT.get_cell_data(r, c, get_displayed)
5299
+ if get_displayed:
5300
+ return self.MT.cell_str(r, c, get_displayed=True)
5301
+ else:
5302
+ return self.MT.get_cell_data(r, c)
5660
5303
 
5661
5304
  def get_row_data(
5662
5305
  self,
@@ -5673,16 +5316,16 @@ class Sheet(tk.Frame):
5673
5316
  raise ValueError(tksheet_type_error("only_columns", ["int", "iterable", "None"], only_columns))
5674
5317
  if r >= self.MT.total_data_rows():
5675
5318
  raise IndexError(f"Row #{r} is out of range.")
5319
+
5676
5320
  if r >= len(self.MT.data):
5677
5321
  total_data_cols = self.MT.total_data_cols()
5678
5322
  self.MT.fix_data_len(r, total_data_cols - 1)
5323
+
5679
5324
  iterable = only_columns if only_columns is not None else range(len(self.MT.data[r]))
5680
- if get_index:
5681
- return [self.get_index_data(r, get_displayed=get_index_displayed)] + [
5682
- self.MT.get_cell_data(r, c, get_displayed=get_displayed) for c in iterable
5683
- ]
5684
- else:
5685
- return [self.MT.get_cell_data(r, c, get_displayed=get_displayed) for c in iterable]
5325
+ f = partial(self.MT.cell_str, get_displayed=True) if get_displayed else self.MT.get_cell_data
5326
+ row = [self.RI.get_cell_data(r, get_displayed=get_index_displayed)] if get_index else []
5327
+ row.extend(f(r, c) for c in iterable)
5328
+ return row
5686
5329
 
5687
5330
  def get_column_data(
5688
5331
  self,
@@ -5698,9 +5341,10 @@ class Sheet(tk.Frame):
5698
5341
  elif not is_iterable(only_rows):
5699
5342
  raise ValueError(tksheet_type_error("only_rows", ["int", "iterable", "None"], only_rows))
5700
5343
  iterable = only_rows if only_rows is not None else range(len(self.MT.data))
5701
- return ([self.get_header_data(c, get_displayed=get_header_displayed)] if get_header else []) + [
5702
- self.MT.get_cell_data(r, c, get_displayed=get_displayed) for r in iterable
5703
- ]
5344
+ f = partial(self.MT.cell_str, get_displayed=True) if get_displayed else self.MT.get_cell_data
5345
+ col = [self.CH.get_cell_data(c, get_displayed=get_header_displayed)] if get_header else []
5346
+ col.extend(f(r, c) for r in iterable)
5347
+ return col
5704
5348
 
5705
5349
  def get_sheet_data(
5706
5350
  self,
@@ -5711,7 +5355,7 @@ class Sheet(tk.Frame):
5711
5355
  get_index_displayed: bool = True,
5712
5356
  only_rows: AnyIter[int] | int | None = None,
5713
5357
  only_columns: AnyIter[int] | int | None = None,
5714
- ) -> list[Any]:
5358
+ ) -> list[list[Any]]:
5715
5359
  if only_rows is not None:
5716
5360
  if isinstance(only_rows, int):
5717
5361
  only_rows = (only_rows,)
@@ -5722,6 +5366,7 @@ class Sheet(tk.Frame):
5722
5366
  only_columns = (only_columns,)
5723
5367
  elif not is_iterable(only_columns):
5724
5368
  raise ValueError(tksheet_type_error("only_columns", ["int", "iterable", "None"], only_columns))
5369
+
5725
5370
  if get_header:
5726
5371
  maxlen = len(self.MT._headers) if isinstance(self.MT._headers, (list, tuple)) else 0
5727
5372
  data = []
@@ -5730,15 +5375,19 @@ class Sheet(tk.Frame):
5730
5375
  if len(r) > maxlen:
5731
5376
  maxlen = len(r)
5732
5377
  if get_index:
5733
- data.append([self.get_index_data(rn, get_displayed=get_index_displayed)] + r)
5378
+ row = [self.RI.get_cell_data(rn, get_displayed=get_index_displayed)]
5379
+ row.extend(r)
5380
+ data.append(row)
5734
5381
  else:
5735
5382
  data.append(r)
5736
5383
  iterable = only_columns if only_columns is not None else range(maxlen)
5737
- if get_index:
5738
- return [[""] + [self.get_header_data(cn, get_displayed=get_header_displayed) for cn in iterable]] + data
5739
- else:
5740
- return [[self.get_header_data(cn, get_displayed=get_header_displayed) for cn in iterable]] + data
5741
- elif not get_header:
5384
+ header_row = [""] if get_index else []
5385
+ header_row.extend(self.CH.get_cell_data(cn, get_displayed=get_header_displayed) for cn in iterable)
5386
+ result = [header_row]
5387
+ result.extend(data)
5388
+ return result
5389
+
5390
+ else:
5742
5391
  iterable = only_rows if only_rows is not None else range(len(self.MT.data))
5743
5392
  return [
5744
5393
  self.get_row_data(
@@ -5760,7 +5409,7 @@ class Sheet(tk.Frame):
5760
5409
  get_header_displayed: bool = True,
5761
5410
  only_rows: int | AnyIter[int] | None = None,
5762
5411
  only_columns: int | AnyIter[int] | None = None,
5763
- ) -> Iterator[list[Any]]:
5412
+ ) -> Generator[list[Any]]:
5764
5413
  if only_rows is not None:
5765
5414
  if isinstance(only_rows, int):
5766
5415
  only_rows = (only_rows,)
@@ -5771,11 +5420,13 @@ class Sheet(tk.Frame):
5771
5420
  only_columns = (only_columns,)
5772
5421
  elif not is_iterable(only_columns):
5773
5422
  raise ValueError(tksheet_type_error("only_columns", ["int", "iterable", "None"], only_columns))
5423
+
5774
5424
  if get_header:
5775
5425
  iterable = only_columns if only_columns is not None else range(self.MT.total_data_cols())
5776
- yield ([""] if get_index else []) + [
5777
- self.get_header_data(c, get_displayed=get_header_displayed) for c in iterable
5778
- ]
5426
+ header_row = [""] if get_index else []
5427
+ header_row.extend(self.CH.get_cell_data(c, get_displayed=get_header_displayed) for c in iterable)
5428
+ yield header_row
5429
+
5779
5430
  iterable = only_rows if only_rows is not None else range(len(self.MT.data))
5780
5431
  yield from (
5781
5432
  self.get_row_data(